3 minute read

Mock an imported function and get a handle to verify if it’s called

// isAtLeast18.spec.js
const isAtLeast18 = require("./isAtLeast18");
const isInteger = require("./isInteger");

// The mock factory returns a mocked function
jest.mock("./isInteger", () => jest.fn());

describe("isAtLeast18", () => {
    it("fails if value is not recognised as integer", () => {
        // For this test we'll mock isInteger to return `false`
        isInteger.mockImplementation(() => false);

        expect(isAtLeast18(123)).toBe(false);
        expect(isAtLeast18("abc")).toBe(false);
    });

    it("passes if value is recognised as integer and is at least 18", () => {
        // For this test we'll mock isInteger to return `true`
        isInteger.mockImplementation(() => true);

        expect(isAtLeast18(123)).toBe(true);
        expect(isAtLeast18("abc")).toBe(false);
    });
});

Mock a node module function

describe('AddService', () => {
  const mockNavigate = jest.fn()
  jest.spyOn(Navigation, 'useNavigation').mockReturnValue({
    navigate: mockNavigate,
  })

  it('should navigate to ServiceParentList with Symptom type', () => {
    render(<AddService />, { wrapper })

    fireEvent.press(screen.getByTestId('pressable-symptom'))

    expect(mockNavigate).toHaveBeenCalledWith(
      RouteNames.ServiceParentList,
      { job: mockJob, type: ServiceType.SYMPTOM }
    )
  })

ReferenceError: Cannot access ‘users’ before initialisation

The error occurs when you use mockReturnValue because the jest.mock() function is hoisted above the users array, causing the users array to be referenced before it is initialised.

To fix this issue, use the jest.mock() factory parameter to access the users array after it has been initialised.

import { handler } from '../../../src/get-user/index'
import { getUsers } from '../../../src/common/usersRepository'

const users = [
  {
    companyId: 'CT01',
    email: 'first.last@navienuk.com',
    companyName: 'London Service Center',
    firstname: 'first',
    gasSafetyNumber: '000000',
    lastname: 'lasts',
    oftecNumber: 'C000000',
  },
]
jest.mock('../../../src/common/usersRepository', () => ({
  getUsers: jest.fn().mockImplementation(() => [users, '200', '']),
}))

describe('getUsers', () => {
  const event = {
    queryStringParameters: {
      companyId: 'companyId',
    },
  }

  it('should return users by the companyId', async () => {
    const result = await handler(event)

    expect(result.statusCode).toEqual('200')
    expect(result.body).toEqual(
      JSON.stringify({
        data: users,
        message: 'Success',
      })
    )
    expect(getUsers).toHaveBeenCalledWith('companyId')
  })
})

Manual mock

A manual mock in Jest is a custom implementation of a module that you want to use in place of the real module in your tests. The purpose of using a manual mock is to isolate your tests from the implementation details of the module and control its behavior in a way that is relevant to your test cases.

A manual mock is created by creating a mock file in a __mocks__ directory and defining the mock implementation for the module. When you import the module in your test file, Jest will automatically use the mock implementation instead of the actual module.

Here’s an example of how you can create a manual mock for a module named moduleA:

  • Create a __mocks__ directory in the same folder as your test file.

  • In the __mocks__ directory, create a file named moduleA.js

To mock a scoped module called @scope/project-name, create a file at __mocks__/@scope/project-name.js, creating the @scope/ directory accordingly.

root
| -- node_modules
| -- __mocks__
    | -- react-native-keyboard-aware-scroll-view.ts

export const KeyboardAwareScrollView = () =>
  jest.fn().mockImplementation(
    ({ children }) => children
  )

spyOn

spyOn is a method provided by Jest that allows you to create a mock function (i.e., a spy) that wraps the original function. A spy allows you to monitor the behaviour of the original function, including how many times it was called, what arguments it was called with, and what it returned.


describe('AddService', () => {
  const mockNavigate = jest.fn()
  jest.spyOn(Navigation, 'useNavigation').mockReturnValue({
    navigate: mockNavigate,
  })

  it('should navigate to ServiceParentList', () => {
    render(<AddService />, {wrapper})

    fireEvent.press(screen.getByTestId('pressable-symptom'))

    expect(mockNavigate).toHaveBeenCalledWith(
      RouteNames.ServiceParentList,
      { job: mockJob, type: ServiceType.SYMPTOM }
    )
  })
})

Mock ES6 class

@aws-sdk/client-s3 package is a javascript class. To use, you have to create an instance.

import { S3 } from '@aws-sdk/client-s3'

const s3 = new S3({ region: config.region })
job.photos.forEach(async photo => {
  await s3.copyObject({
    Bucket: config.photo_storage_bucket_name,
    CopySource: `${config.photo_storage_bucket_name}/${photo.shortFilename}`,
    Key: photo.shortFilename,
    MetadataDirective: 'REPLACE',
    ContentType: 'image/jpeg',
  })
})

To mock this, you can simply use jest.mock()

Calling jest.mock('') returns a useful “automatic mock” you can use to spy on calls to the class constructor and all of its methods. It replaces the ES6 class with a mock constructor, and replaces all of its methods with mock functions that always return undefined. Method calls are saved in theAutomaticMock.mock.instances[index].methodName.mock.calls

jest.mock('@aws-sdk/client-s3')

Tags: ,

Updated:

Comments