Jest: Mock ES6 Module with both default and named export - javascript

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?

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'

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.

Related

TypeError: Cannot read property 'fraction' of undefined - Cypress/Javascript

I am doing a test where I grab an odds value and store it as a fraction. Then I want to compare the value to a particular format depending on the option selected from the drop down.
I am trying to use these to set up the fraction and determine the odds format:
https://mathjs.org/docs/datatypes/fractions.html
How do I resolve that type error above.
Screenshot:
The mathjs has no default export, so you import everything (*) and then name it in your import
import * as math from 'mathjs'
This is the main entry point for the mathjs package.
// configuration
export { config } from './configReadonly.js'
// functions and constants
export * from './pureFunctionsAny.generated.js'
export * from './impureFunctionsAny.generated.js'
export * from './typeChecks.js'
// error classes
export { IndexError } from '../error/IndexError.js'
export { DimensionError } from '../error/DimensionError.js'
export { ArgumentsError } from '../error/ArgumentsError.js'
// dependency groups
export * from './dependenciesAny.generated.js'
// factory functions
export * from '../factoriesAny.js'
// core
export { create } from '../core/create.js'
export { factory } from '../utils/factory.js'
If it had a default export, there would be
export default {
function1,
function2,
function3,
...
}
and then you can import it without using * as math.
If you want to use just fraction you can use:
const { fraction } = require("mathjs");
//In your test
fraction(oddsValue);
If you want to use others as well, you can do:
import { create, all } from "mathjs"
const math = create(all, {})
//In your test
math.fraction(oddsValue)

Test React component with imported functions [duplicate]

I want to test that one of my ES6 modules calls another ES6 module in a particular way. With Jasmine this is super easy --
The application code:
// myModule.js
import dependency from './dependency';
export default (x) => {
dependency.doSomething(x * 2);
}
And the test code:
//myModule-test.js
import myModule from '../myModule';
import dependency from '../dependency';
describe('myModule', () => {
it('calls the dependency with double the input', () => {
spyOn(dependency, 'doSomething');
myModule(2);
expect(dependency.doSomething).toHaveBeenCalledWith(4);
});
});
What's the equivalent with Jest? I feel like this is such a simple thing to want to do, but I've been tearing my hair out trying to figure it out.
The closest I've come is by replacing the imports with requires, and moving them inside the tests/functions. Neither of which are things I want to do.
// myModule.js
export default (x) => {
const dependency = require('./dependency'); // Yuck
dependency.doSomething(x * 2);
}
//myModule-test.js
describe('myModule', () => {
it('calls the dependency with double the input', () => {
jest.mock('../dependency');
myModule(2);
const dependency = require('../dependency'); // Also yuck
expect(dependency.doSomething).toBeCalledWith(4);
});
});
For bonus points, I'd love to make the whole thing work when the function inside dependency.js is a default export. However, I know that spying on default exports doesn't work in Jasmine (or at least I could never get it to work), so I'm not holding out hope that it's possible in Jest either.
Edit: Several years have passed and this isn't really the right way to do this any more (and probably never was, my bad).
Mutating an imported module is nasty and can lead to side effects like tests that pass or fail depending on execution order.
I'm leaving this answer in its original form for historical purposes, but you should really use jest.spyOn or jest.mock. Refer to the jest docs or the other answers on this page for details.
Original answer follows:
I've been able to solve this by using a hack involving import *. It even works for both named and default exports!
For a named export:
// dependency.js
export const doSomething = (y) => console.log(y)
// myModule.js
import { doSomething } from './dependency';
export default (x) => {
doSomething(x * 2);
}
// myModule-test.js
import myModule from '../myModule';
import * as dependency from '../dependency';
describe('myModule', () => {
it('calls the dependency with double the input', () => {
dependency.doSomething = jest.fn(); // Mutate the named export
myModule(2);
expect(dependency.doSomething).toBeCalledWith(4);
});
});
Or for a default export:
// dependency.js
export default (y) => console.log(y)
// myModule.js
import dependency from './dependency'; // Note lack of curlies
export default (x) => {
dependency(x * 2);
}
// myModule-test.js
import myModule from '../myModule';
import * as dependency from '../dependency';
describe('myModule', () => {
it('calls the dependency with double the input', () => {
dependency.default = jest.fn(); // Mutate the default export
myModule(2);
expect(dependency.default).toBeCalledWith(4); // Assert against the default
});
});
You have to mock the module and set the spy by yourself:
import myModule from '../myModule';
import dependency from '../dependency';
jest.mock('../dependency', () => ({
doSomething: jest.fn()
}))
describe('myModule', () => {
it('calls the dependency with double the input', () => {
myModule(2);
expect(dependency.doSomething).toBeCalledWith(4);
});
});
Fast forwarding to 2020, I found this blog post to be the solution: Jest mock default and named export
Using only ES6 module syntax:
// esModule.js
export default 'defaultExport';
export const namedExport = () => {};
// esModule.test.js
jest.mock('./esModule', () => ({
__esModule: true, // this property makes it work
default: 'mockedDefaultExport',
namedExport: jest.fn(),
}));
import defaultExport, { namedExport } from './esModule';
defaultExport; // 'mockedDefaultExport'
namedExport; // mock function
Also one thing you need to know (which took me a while to figure out) is that you can't call jest.mock() inside the test; you must call it at the top level of the module. However, you can call mockImplementation() inside individual tests if you want to set up different mocks for different tests.
To mock an ES6 dependency module default export using Jest:
import myModule from '../myModule';
import dependency from '../dependency';
jest.mock('../dependency');
// If necessary, you can place a mock implementation like this:
dependency.mockImplementation(() => 42);
describe('myModule', () => {
it('calls the dependency once with double the input', () => {
myModule(2);
expect(dependency).toHaveBeenCalledTimes(1);
expect(dependency).toHaveBeenCalledWith(4);
});
});
The other options didn't work for my case.
Adding more to Andreas' answer. I had the same problem with ES6 code, but I did not want to mutate the imports. That looked hacky. So I did this:
import myModule from '../myModule';
import dependency from '../dependency';
jest.mock('../dependency');
describe('myModule', () => {
it('calls the dependency with double the input', () => {
myModule(2);
});
});
And added file dependency.js in the " __ mocks __" folder parallel to file dependency.js. This worked for me. Also, this gave me the option to return suitable data from the mock implementation. Make sure you give the correct path to the module you want to mock.
The question is already answered, but you can resolve it like this:
File dependency.js
const doSomething = (x) => x
export default doSomething;
File myModule.js
import doSomething from "./dependency";
export default (x) => doSomething(x * 2);
File myModule.spec.js
jest.mock('../dependency');
import doSomething from "../dependency";
import myModule from "../myModule";
describe('myModule', () => {
it('calls the dependency with double the input', () => {
doSomething.mockImplementation((x) => x * 10)
myModule(2);
expect(doSomething).toHaveBeenCalledWith(4);
console.log(myModule(2)) // 40
});
});
None of the answers here seemed to work for me (the original function was always being imported rather than the mock), and it seems that ESM support in Jest is still work in progress.
After discovering this comment, I found out that jest.mock() does not actually work with regular imports, because the imports are always run before the mock (this is now also officially documented). Because of this, I am importing my dependencies using await import(). This even works with a top-level await, so I just have to adapt my imports:
import { describe, expect, it, jest } from '#jest/globals';
jest.unstable_mockModule('../dependency', () => ({
doSomething: jest.fn()
}));
const myModule = await import('../myModule');
const dependency = await import('../dependency');
describe('myModule', async () => {
it('calls the dependency with double the input', () => {
myModule(2);
expect(dependency.doSomething).toBeCalledWith(4);
});
});
I solved this another way. Let's say you have your dependency.js
export const myFunction = () => { }
I create a depdency.mock.js file besides it with the following content:
export const mockFunction = jest.fn();
jest.mock('dependency.js', () => ({ myFunction: mockFunction }));
And in the test, before I import the file that has the dependency, I use:
import { mockFunction } from 'dependency.mock'
import functionThatCallsDep from './tested-code'
it('my test', () => {
mockFunction.returnValue(false);
functionThatCallsDep();
expect(mockFunction).toHaveBeenCalled();
})
I tried all the solutions and none worked or were showing lots of TS errors.
This is how I solved it:
format.ts file:
import camelcaseKeys from 'camelcase-keys'
import parse from 'xml-parser'
class Format {
parseXml (xml: string) {
return camelcaseKeys(parse(xml), {
deep: true,
})
}
}
const format = new Format()
export { format }
format.test.ts file:
import format from './format'
import camelcaseKeys from 'camelcase-keys'
import parse from 'xml-parser'
jest.mock('xml-parser', () => jest.fn().mockReturnValue('parsed'))
jest.mock('camelcase-keys', () => jest.fn().mockReturnValue('camel cased'))
describe('parseXml', () => {
test('functions called', () => {
const result = format.parseXml('XML')
expect(parse).toHaveBeenCalledWith('XML')
expect(camelcaseKeys).toHaveBeenCalledWith('parsed', { deep: true })
expect(result).toBe('camel cased')
})
})
I made some modifications on #cam-jackson original answer and side effects has gone. I used lodash library to deep clone the object under test and then made any modification I want on that object. But be ware that cloning heavy objects can have negative impact on test performance and test speed.
objectUndertest.js
const objectUnderTest = {};
export default objectUnderTest;
objectUnderTest.myFunctionUnterTest = () => {
return "this is original function";
};
objectUndertest.test.js
import _ from "lodash";
import objectUndertest from "./objectUndertest.js";
describe("objectUndertest", () => {
let mockObject = objectUndertest;
beforeEach(() => {
mockObject = _.cloneDeep(objectUndertest);
});
test("test function", () => {
mockObject.myFunctionUnterTest = () => {
return "this is mocked function.";
};
expect(mockObject.myFunctionUnterTest()).toBe("this is mocked function.");
});
});

How can I export all functions from a file in JS?

I'm creating a unit converter, and I want to put all of the conversion functions into their own file. Using ES6 export, is there any way to export all of the functions in the file with their default names using only one line? For example:
export default all;
The functions are all just in the file, not within an object.
No, there's no wildcard export (except when you're re-exporting everything from another module, but that's not what you're asking about).
Simply put export in front of each function declaration you want exported, e.g.
export function foo() {
// ...
}
export function bar() {
// ...
}
...or of course, if you're using function expressions:
export var foo = function() {
// ...
};
export let bar = () => {
// ...
};
export const baz = value => {
// ...
};
I think there are a lot of solutions to this. And as has been answered, there's no wildcard export. But, you can 'wildcard' the import. So, I much prefer the one putting export before each of the functions you want to expose from the file:
//myfile.js
export function fn1() {...}
export function fn2() {...}
and then import it like so:
import * as MyFn from './myfile.js'
Afterwards you could use it like so:
MyFn.fn1();
MyFn.fn2();
You can also use module.exports as follows:
function myFunction(arg) {
console.debug(arg);
}
function otherFunction(arg) {
console.error(arg);
}
module.exports = {
myFunction: myFunction,
otherFunction: otherFunction,
};
Then you can import it:
import {myFunction, otherFunction} from "./Functions.js";
In my use case, I do have three reusable functions in one file.
utils/reusables.js
export const a = () => {}
export const b = () => {}
export const c = () => {}
In order to point the root folder instead of individual file names, I created a file called index.js which will comprise of all the functions that are listed in individual files.
utils/index.js
export * from './reusables'
Now, when I want to use my a function, I will have to simply import it like this
import { a } from '../utils'
Rather than calling it from its individual files
import { a } from '../utils/reusables'
You could also export them at the bottom of your script.
function cube(x) {
return x * x * x;
}
const foo = Math.PI + Math.SQRT2;
var graph = {
options: {
color:'white',
thickness:'2px'
},
draw: function() {
console.log('From graph draw function');
}
}
export { cube, foo, graph };
You can also aggregate submodules together in a parent module so that they are available to import from that module.
// In parentModule.js
export { myFunction, myVariable } from 'childModule1.js';
export { myClass } from 'childModule2.js';
// In top-level module
import { myFunction, myVariable, myClass } from 'parentModule.js'
For Node.js environment, what I did to export functions was this.
UserController.js
module.exports = {
signUp: () => {
return "user"
},
login: () => {
return "login"
}
}
UserRouter.js
const UserController = require('./UserController')
then login and signUp functions could be used inside UserRouter as UserController.signUp() and UserController.login()
I think there's a missing common solution, which is exporting in index.js file:
myModule/myFunctions.js
export const foo = () => { ... }
export const bar = () => { ... }
then in myModule/index.js
export * from "./myFunctions.js";
This way you can simply import and use it with:
import { foo, bar } from "myModule";
foo();
bar();
functions.js
function alpha(msj) {
console.log('In alpha: ' + msj);
}
function beta(msj) {
console.log('In beta: ' + msj);
}
module.exports = {
alpha,
beta
};
main.js
const functions = require('./functions');
functions.alpha('Hi');
functions.beta('Hello');
Run
node main.js
Output
In alpha: Hi
In beta: Hello
In case anyone still needs an answer to this in modern JavaScript:
const hello = () => "hello there"
const bye = () => "bye bye"
export default { hello, bye }
What I like to do is to export all functions within an object:
//File.js
export default {
testFunction1: function testFunction1(){
console.log("Hello World")
},
//a little bit cleaner
testFunction2: () => {
console.log("Nothing here")
}
}
Now you can access the functions with calling the key value of the object:
//differentFile.js
import file from 'File.js'
file.testFunction1()
//Hello World
file.testFunction2()
//Nothing here

Correct way to export object in es6 module

I'm trying to export an my module as an object but exporting it seems an 'anti pattern' (https://medium.com/#rauschma/note-that-default-exporting-objects-is-usually-an-anti-pattern-if-you-want-to-export-the-cf674423ac38)
So I was wondering what's the correct way to export an object and then use it as
import utils from "./utils"
`
utils.foo()
Currently I'm doing like so
/** a.js **/
function foo(){
//...
}
export {
foo
}
/** b.js **/
import * as utils from "a";
utils.foo()
is it correct like so? Do I maintain the tree-shaking feature?
thanks
If the object you want to import/export only contains some functions (as I assume due to the Utils name), you can export the functions separately as follows:
export function doStuff1() {}
export function doStuff2() {}
And import like this:
import {doStuff1, doStuff2} from "./myModule";
However, if the object you want to export holds state in addition to methods, you should stick to a simple export default myObject. Otherwise, calling the imported methods won't work as intended, since the context of the object is lost.
As an example, the following object should be exported as a whole, since the properties of the object should stay encapsulated. Only importing and calling the increment function would not mutate myObject since the context of the object cannot be provided (since it's not imported as a whole).
const myObject = {
counter: 0,
increment: function() {
this.counter++;
}
}
export default myObject;
es6 native way to do this:
// file1.es6
export const myFunc = (param) => {
doStuff(param)
}
export const otherFunc = ({ param = {} }) => {
doSomething({ ...param })
}
// file2.es6
import { otherFunc } from './file1.es6'
import * as MyLib from './file1.es6'
MyLib.myfunc(0)
MyLib.otherFunc({ who: 'Repley' })
otherFunc({ var1: { a1: 1 } })
And so on.

es2015 re-export module and override single export function of the re-exported module

I want to re-export a whole module and override only a specific function of the re-exported module. But it seems exporting the override function doesn't get processed when the same function is already re-rexported.
(http://www.ecma-international.org/ecma-262/6.0/#sec-module-semantics-static-semantics-early-errors, 'It is a Syntax Error if the ExportedNames of ModuleItemList contains any duplicate entries.')
The motivation behind my approach is to minimize explicit re-exporting a very big or long module, if I only want to override a specific function or method in the re-exported module.
Is there any way to implement my approach in es6/es2015?
My code so far:
module-a.js
export class MyFirstStandardClass {
sendMeMessages() {
return `hello, I'm a standard implementation`;
}
}
export function talkToMe() {
return `standard talking: how are you doing?`;
}
module-b.js
import * as StandardModule from 'module-a';
export function talkToMe(condition = true) {
if (condition) {
return `project conditional talking: ${StandardModule.talkToMe()}`;
}
return `project without a condition!`;
}
export * from 'module-a';
module-c.js
import * as MyModule from 'module-b';
import React, { Component } from 'react';
export default class App extends Component {
componentWillMount() {
console.log(MyModule);
this.myFirstStandardInstance = new MyModule.MyFirstStandardClass();
}
render() {
return (
<div>
<label>
Class
</label>
<div>
{ this.myFirstStandardInstance.sendMeMessages() }
</div>
<label>
Function
</label>
<div>
{ MyModule.talkToMe(true) } // returns 'standard talking: how are you doing?'; expected 'project conditional talking: standard talking: how are you doing?'
</div>
</div>
);
}
}
It seems my first solution should work. According to the ECMAScript spec local exports should have priority. (http://www.ecma-international.org/ecma-262/6.0/#sec-getexportednames)
It's an issue in the Babel transpiler. More info: https://github.com/systemjs/systemjs/issues/1031#issuecomment-171262430
Issue in Babel: https://phabricator.babeljs.io/T6967
You can select which modules from module-a to export on one line. So in your module-b.js you can do:
// export all modules excluding `talkToMe`
export { MyFirstStandardClass, someOtherModule } from 'module-a';
export function talkToMe(condition = true) {
// ...
}
Or you can export default object and choose what to exclude/override with Object.assign():
import * as StandardModule from 'module-a';
const overridenExports = {
talkToMe: function(condition = true) {
// ...
}
}
const myModule = Object.assign({}, StandardModule, overridenExports);
export default myModule;
and import default like:
import MyModule from 'module-b';

Categories

Resources