Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest: Mock ES6 Module with both default and named export

I have an ES6 module with both a default and a named export:

/** /src/dependency.js **/

export function utilityFunction() { return false; }

export default function mainFunction() { return 'foo'; }

Its being used by a second ES6 module:

/** /src/myModule.js **/

import mainFunction, { utilityFunction } from './dependency';

// EDIT: Fixed syntax error in code sample
// export default myModule() {
export default function myModule() {
    if (!utilityFunction()) return 2;
    return mainFunction();
}

I'm trying to write a unit test for myModule.js using Jest. But when I try to mock both the named and the default import, Jest appears to only mock the named import. It continues to use the actual implementation of the default import, and doesn't allow me to mock it, even after I call .mockImplementation(). Here's the code I'm trying to use:

/** 
  * Trying to mock both named and default import. 
  * THIS DOESN'T WORK.
  */

/** /tests/myModule.test.js **/

import mainFunction, { utilityFunction } from '../src/dependency';
import myModule from '../src/myModule';

jest.mock('../src/dependency');

mainFunction.mockImplementation(() => 1);
utilityFunction.mockImplementation(() => true);

describe('myModule', () => {
    it('should return the return value of mainFunction when the result of utilityFunction is true', () => {
        expect(myModule()).toEqual(1); // FAILS - actual result is 'foo'
    });
});

This behavior seems really strange to me, because when mocking JUST default imports or JUST named imports, this API works fine. For example, in the case where myModule.js only imports a default import, this is pretty easily done:

/**
  * Trying to mock just the default import. 
  * THIS WORKS.
  */

/** /src/myModule.js **/

import mainFunction from './dependency';

// EDIT: Fixed syntax error in code sample
// export default myModule() {
export default function myModule() {
    return mainFunction();
}


/** /tests/myModule.test.js **/
// If only mainFunction is used by myModule.js

import mainFunction from '../src/dependency';
import myModule from '../src/myModule';

jest.mock('../src/dependency');
mainFunction.mockImplementation(() => 1);

describe('myModule', () => {
    it('should return the return value of mainFunction', () => {
        expect(myModule()).toEqual(1); // Passes
    });
});

In the case where only the named 'utilityFunction' export is used, its also pretty easy to mock the import:

/**
  * Trying to mock both named and default import. 
  * THIS WORKS.
  */
/** /src/myModule.js **/

import { utililtyFunction } from './dependency';

// EDIT: Fixed syntax error in code sample
// export default myModule()
export default function myModule() {
    return utilityFunction();
}


/** /tests/myModule.test.js **/
// If only utilityFunction is used by myModule.js

import { utilityFunction } from '../src/dependency';
import myModule from '../src/myModule';

jest.mock('../src/dependency);
utilityFunction.mockImplementation(() => 'bar');

describe('myModule', () => {
    it('should return the return value of utilityFunction', () => {
        expect(myModule()).toEqual('bar'); // Passes
    });
});

Is it possible to mock both the named and default import using Jest? Is there a different syntax that I can use to achieve the result I want, where I import both named and default values from a module and am able to mock them both?

like image 433
bean Avatar asked Feb 14 '18 23:02

bean


People also ask

How do you mock a default export component in Jest?

Default Export To mock a React component, the most straightforward approach is to use the jest. mock function. You mock the file that exports the component and replace it with a custom implementation. Since a component is basically a function, the mock should also return a function.

What is export default and named export in ES6?

Exports without a default tag are Named exports. Exports with the default tag are Default exports. Using one over the other can have effects on your code readability, file structure, and component organization. Named and Default exports are not React-centric ideas. They are es6 features.

How do you mock a default export?

In order to successfully mock a module with a default export, we need to return an object that contains a property for __esModule: true and then a property for the default export. This helps Jest correctly mock an ES6 module that uses a default export. expect(method1()).

How do you mock a named export in Jest?

In order to mock named exports in Jest, you need to import all named exports from a file with an * and assign jest. fn to the method that needs to be mocked. mockImplementation expects a callback function to be passed that describes the implementation.


2 Answers

The other solution didn't work for me. This is how I did:

  jest.mock('../src/dependency', () => ({
    __esModule: true,
    utilityFunction: 'utilityFunction',
    default: 'mainFunction'
  }));

Another way to do it:

jest.unmock('../src/dependency');

const myModule = require('../src/dependency');
myModule.utilityFunction = 'your mock'
like image 97
Albert Olivé Avatar answered Oct 12 '22 23:10

Albert Olivé


You have a syntax error ... the function keyword is omitted from the default export in myModule.js. Should look like this:

import mainFunction, { utilityFunction } from './dependency';

export default function myModule() {
    if (!utilityFunction()) return 2;
    return mainFunction();
}

I'm not sure how you got the test to run otherwise, but I just tried this out locally and it passed.

like image 36
djfdev Avatar answered Oct 12 '22 23:10

djfdev