Loose match one value in jest.toHaveBeenCalledWith

To re-iterate the comment by cl0udw4lk3r as I found this the most useful in my scenario:

If you have a method that accepts multiple parameters (not an object) and you only want to match some of these parameters then you can use the expect object.

Example

method I want to test:

client.setex(key, ttl, JSON.stringify(obj));

I want to ensure the correct values are passed into the key and ttl but I'm not concerned what the object passed in is. So I set up a spy:

const setexSpy = jest.spyOn(mockClient, "setex");

and I can then expect this scenario thus:

expect(setexSpy).toHaveBeenCalledWith('test', 99, expect.anything());

You can also use more strongly typed calls using expect.any (expect.any(Number)) etc.


You can access the expected object for a better assertion using track.mock.calls[0][0] (the first [0] is the invocation number, and the second [0] is the argument number). Then you could use toMatchObject to find partially match the object, avoiding the dynamic parameters such as intervalInMilliseconds.


This can be done with asymmetric matchers (introduced in Jest 18)

expect(track).toHaveBeenCalledWith(
  expect.objectContaining({
   "action": "PublicationPage", 
   "category": "PublicationPage", 
   "label": "7",
   "name": "n/a"
  })
)

If you use jest-extended you can do something like

expect(track).toHaveBeenCalledWith(
  expect.objectContaining({
   "action": "PublicationPage", 
   "category": "PublicationPage", 
   "label": "7",
   "name": "n/a",
   "intervalInMilliseconds": expect.toBeWithin(999, 1002)
  })
)

Tags:

Jestjs