Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking an ES6 class function with Jest

I have a question about how can I mock an ES6 class instance using Jest which is used by the method I actually want to test. My real case is trying to test a Redux async action creator that make a request and dispatch some action depending on the request result.

This is a simplified example of the use case :

// communication.js
// An exported ES6 class module with proxy to the request library.
import post from './post';
export default class communication {

    getData(data, success, error) {
        const res = post(data);
        if(res) {
            success();
        } else {
            error();
        }
    }
}

// communicatorAssist.js
// A redux async function using communication.js
import communication from './communication';
// ...

export function retrieveData() {
    return dispatch => {
        const data = { name: 'michel'};
        communication.getData(data,
            (res) => dispatch(successAction(res)),
            (res) => dispatch(errorAction(res));
    }
}

// communicatorAssist.test.js testing the communicatorAssist
import { retrieveData } from 'communicatorAssist';

// communication.getData should call success callback
// for this test.
it('Should call the success callback', () => {
    retrieveData();
    // Assert that mocked redux store contains actions
});

// communication.getData should call error callback
// for this test.
it('Should call the error callback', () => {
    retrieveData();
    // Assert that mocked redux store contains actions
});

What I want is mocking the communication class in the test and change the behaviour of the getData() function in each test to call success and error callbacks without any call to post method.

I only success to mock the getData() function for the whole test file with this snippet at the top of it :

import communication from '../communication'
jest.mock('../communication', () => (() => ({
    getData: (success, error) => success()
})));

but I can't switch between implementation in different test case.

I figure that something using .mockImplementation() could do the stuff but I can't make this work in my case (I saw examples using it for module exporting functions but not for classes ).

Does anyone have an idea ?

Edit :

I forgot a part in the code exemple : the communication class instance creation which I think is the "problem" for mocking it :

const com = new communication();

If com is instanciated at a global level in the communicatorAssist.js file : it fail with communication.getData is not a function error.

But if I set the instanciation inside the retrieveData() function, Andreas Köberle snippet work's fine :

import communication from '../communication'
jest.mock('../communication', () => jest.fn());

communication.mockImplementation(
  () => ({
    getData: (success, error) => success()
  })
)

(jest.mock() factory parameter need to return a function not directly jest.fn)

I don't know why it's not working using a file global scope instance.

like image 807
Imk Avatar asked Sep 30 '17 07:09

Imk


People also ask

How do you spy a function in Jest?

To spy on an exported function in jest, you need to import all named exports and provide that object to the jest. spyOn function. That would look like this: import * as moduleApi from '@module/api'; // Somewhere in your test case or test suite jest.

How do you test a method in Jest?

To test method implementation using spies with Jest we use the jest. spyOn() function. jest. spyOn() is called with two required parameters - the object and the object method identifier we're spying on.

How do you mock the return value of a function in Jest?

To mock a function's return value in Jest, you first need to import all named exports from a module, then use mockReturnValue on the imported function. You can use the * as <alias> inside an import statement to import all named exports. Then, you need to chain mockReturnValue off of jest.


1 Answers

You need to mock the module with jest.fn() then you can import it and change the behaviour of it using mockImplementation:

import communication from '../communication'
jest.mock('../communication', jest.fn());

communication.mockImplementation(
  () => ({
    getData: (success, error) => success()
  })
)
like image 164
Andreas Köberle Avatar answered Sep 27 '22 23:09

Andreas Köberle