Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock callback functions with jest

I'm trying to mock a custom function with jest but I'm having problems with it.

This is my function:

export const resizeImage = (file, fileName, callback) => {
  const MAX_WIDTH = avatarImage.maxWidth;
  const MAX_HEIGHT = avatarImage.maxHeight;
  const img = document.createElement('img');
  img.src = window.URL.createObjectURL(file);
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');

  img.onload = () => {
    const sizes = internalResizeImage(img, MAX_WIDTH, MAX_HEIGHT);

    canvas.width = sizes.width;
    canvas.height = sizes.height;
    ctx.drawImage(img, 0, 0, sizes.width, sizes.height);
    return callback(dataURItoFile(canvas.toDataURL(), fileName));
  };
};

I called like this:

resizeImage(acceptedFiles[0], this.props.user.id, (res) => {
  //dostuff
});

In my test I'm mocking it like this:

let mockResizeImage = jest.fn();

jest.mock('../../utilities/imageUtils', () => ({
  resizeImage: () => mockResizeImage
}));

I want mockResizeImage to be a callback and then in my test change the returning values:

it('should call handleDrop and accept files', () => {
    //mockResizeImage.mockReturnValue('something');

    const instance = shallow(mockComponent()).instance();
    const acceptFilesMock = ['test'];

    instance.handleDrop(acceptFilesMock);

    expect(clickSpy).toHaveBeenCalledTimes(1);
  });

If it were a promise, all good, but it's a callback and I don't know what I'm doing wrong.

Thanks.

like image 241
Albert Olivé Avatar asked May 04 '17 16:05

Albert Olivé


People also ask

How do you mock a callback Jest?

jest. mock('../../utilities/imageUtils', () => ({ resizeImage: (file, fileName, callback) => callback('someData') })); import {resizeImage} from '../../utilities/imageUtils' jest. mock('../../utilities/imageUtils', () => ({ resizeImage: jest.

How do you mock a function inside a function using Jest?

To mock inner function with Jest and JavaScript, we should export the inner function in a module. import * as funcBModule from "./funcB"; import { funcA } from "./foo"; describe("helper", () => { test("test funcB", () => { expect(funcBModule. funcB()). toBe("original"); }); test("test funcA", () => { const spy = jest.

How do you test a function is called in Jest?

How to check if a function was called correctly with Jest? To check if a function was called correctly with Jest we use the expect() function with specific matcher methods to create an assertion. We can use the toHaveBeenCalledWith() matcher method to assert the arguments the mocked function has been called with.


2 Answers

You can mock a module with a function that accepts the same parameter as your original one, and instantly call the callback:

jest.mock('../../utilities/imageUtils', () => ({
  resizeImage: (file, fileName, callback) => callback('someData')
}));

Btw. the way you mock the module in your question can't work because of the way jest.mock works. Even if you write it after the let statement, it will be hoisted to the top of the file when the test is been compiled. So the best way to mock the function with a spy would look like this:

import {resizeImage} from '../../utilities/imageUtils'

jest.mock('../../utilities/imageUtils', () => ({
  resizeImage: jest.fn((file, fileName, callback) => callback('someData'))
}));

Now you have the same behaviour as above but you can also test that resizeImage was called with the correct parameters.

As your last parameter is a function you can either just test for the 2 first params like this using mock.calls:

expect(resizeImage.mock.calls[0][0]).toBe('firstParameter')
expect(resizeImage.mock.calls[0][1]).toBe('secondParameter')

Or use a wildcard for the last parameter when using toBeCalledWith using expect.anything():

expect(resizeImage).toBeCalledWith('firstParameter', 'secondParameter', expect.anything()); 
like image 192
Andreas Köberle Avatar answered Sep 18 '22 16:09

Andreas Köberle


Make sure when you call the actual function by passing the callback function as one of the arguments, that function is being called from inside the test block like below

function forEach(items, callback) {
  for (let index = 0; index < items.length; index++) {
    callback(items[index]);
  }
}
const mockCallback = jest.fn((x) => x + 1);

test("fn", () => {
  forEach([0, 1, 2], mockCallback);
  expect(mockCallback.mock.calls.length).toBe(3);
});

And not like below

function forEach(items, callback) {
      for (let index = 0; index < items.length; index++) {
        callback(items[index]);
      }
    }
const mockCallback = jest.fn((x) => x + 1);
forEach([0, 1, 2], mockCallback);
    
test("fn", () => {
   expect(mockCallback.mock.calls.length).toBe(3);
});
like image 28
Rishab Surana Avatar answered Sep 16 '22 16:09

Rishab Surana