Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to assert function invocation order in jest

Tags:

I am mocking two functions with with jest.fn:

let first = jest.fn();
let second = jest.fn();

How can I assert that first called before second?

What I am looking for is something like sinon's .calledBefore assertion.

Update I used this simple "temporary" workaround

it( 'should run all provided function in order', () => {

  // we are using this as simple solution
  // and asked this question here https://stackoverflow.com/q/46066250/2637185

  let excutionOrders = [];
  let processingFn1  = jest.fn( () => excutionOrders.push( 1 ) );
  let processingFn2  = jest.fn( () => excutionOrders.push( 2 ) );
  let processingFn3  = jest.fn( () => excutionOrders.push( 3 ) );
  let processingFn4  = jest.fn( () => excutionOrders.push( 4 ) );
  let data           = [ 1, 2, 3 ];
  processor( data, [ processingFn1, processingFn2, processingFn3, processingFn4 ] );

  expect( excutionOrders ).toEqual( [1, 2, 3, 4] );
} );
like image 999
Ahmed Ayoub Avatar asked Sep 06 '17 03:09

Ahmed Ayoub


People also ask

How do you test a function call in Jest?

Here is the working test file: const callnapply = require('./callnapply'); test('testing Function. prototype. call as mock function', () => { const outer = function() {}; outer.

How do you expect a function in Jest?

The expect function is used every time you want to test a value. You will rarely call expect by itself. Instead, you will use expect along with a "matcher" function to assert something about a value. expect(bestLaCroixFlavor()).

How do you mock a nested function in 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.

What are assertions in Jest?

An assertion is a check that values meet certain conditions. In other words, if you use expect. assertions(5) the test will fail unless expect() is called at least 5 times. This is useful for async tests, but it's not the only way to handle asynchronicity, you can find other patterns in the Jest doc.


2 Answers

Instead of your workaround you can install jest-community's jest-extended package which provides support for this via .toHaveBeenCalledBefore(), e.g.:

it('calls mock1 before mock2', () => {
  const mock1 = jest.fn();
  const mock2 = jest.fn();

  mock1();
  mock2();
  mock1();

  expect(mock1).toHaveBeenCalledBefore(mock2);
});

Note: per their doc you need at least v23 of Jest to use this function

https://github.com/jest-community/jest-extended#tohavebeencalledbefore

P.S. - This feature was added a few months after you posted your question, so hopefully this answer still helps!

like image 137
youngrrrr Avatar answered Sep 20 '22 18:09

youngrrrr


The solution by clemenspeters (where he wanted to make sure logout is called before login) works for me:

const logoutSpy = jest.spyOn(client, 'logout');
const loginSpy = jest.spyOn(client, 'login');
// Run actual function to test
await client.refreshToken();
const logoutOrder = logoutSpy.mock.invocationCallOrder[0];
const loginOrder = loginSpy.mock.invocationCallOrder[0];
expect(logoutOrder).toBeLessThan(loginOrder)
like image 20
Luís Ramalho Avatar answered Sep 21 '22 18:09

Luís Ramalho