Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expect jest mock to have been called with an argument fails in react testing library

I would expect this test to pass but it fails:

it('should consume files on drop', () => {
  const mock = jest.fn();
  const file = new File(['file'], 'file.txt', { type: 'text/plain' });
  const fileList = [file];

  render(<DropZone onDocumentDrop={mock} />);

  const dropZone = screen.getByTestId('dropZone');
  const dropEvent = createEvent.drop(dropZone);

  Object.defineProperty(dropEvent, 'dataTransfer', {
    value: {
      files: {
        item: (index: number) => fileList[index],
        length: fileList.length,
      },
    },
  });

  fireEvent(dropZone, dropEvent);

  expect(dropZone).toBeInTheDocument();
  expect(mock).toHaveBeenCalled();
  expect(mock).toHaveBeenCalledWith({
    item: (index: number) => fileList[index],
    length: 1,
  });
});

Jest reports that:

expect(jest.fn()).toHaveBeenCalledWith(...expected)

- Expected
+ Received

- {"item": [Function item], "length": 1},
+ {"item": [Function item], "length": 1},

I am not sure how to make it pass or get anymore insight into what is wrong?

like image 429
RyanP13 Avatar asked Oct 27 '22 17:10

RyanP13


People also ask

What does Jest mock () do?

Mock functions allow you to test the links between code by erasing the actual implementation of a function, capturing calls to the function (and the parameters passed in those calls), capturing instances of constructor functions when instantiated with new , and allowing test-time configuration of return values.

How do you expect a function to be called in 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.

Which method is useful to clean up a mock's usage data between two assertions?

mockFn.mockClear() ​ Often this is useful when you want to clean up a mocks usage data between two assertions.


2 Answers

When checking the arguments of the last function call, you can use expect.objectContaining() to match the received object.

You can also use lastCalledWith() instead of toHaveBeenCalledWith(). They are both the same but I personally prefer the former because it's shorter and easier to read.

const item = (index: number) => []
const args = {
  length: 1,
  item,
}

const mock = jest.fn()

mock(args)

expect(mock).lastCalledWith(
  expect.objectContaining({
    length: expect.any(Number), // or 1 if you know the exact value
    item: expect.any(Function),
  })
)
like image 195
NearHuscarl Avatar answered Dec 19 '22 14:12

NearHuscarl


Two different objects in javascript are not the same value, even if they have the same key/value pairs - An object is stored in memory as a reference and so two different objects have two different references, therefore they are not equal.

Try defining the object once instead and passing it's reference around:

const files = {
    item: (index: number) => fileList[index],
    length: fileList.length,
};

Object.defineProperty(dropEvent, 'dataTransfer', { value: { files, }, });
// -- snip --- //
expect(mock).toHaveBeenCalledWith(files);
like image 20
Dylan Kerler Avatar answered Dec 19 '22 14:12

Dylan Kerler