How to test the following:
// File: index.js
export function myName(text) {
return 'My name is: ' + text;
}
export function makeBold(text) {
return '<strong>' + myName(text) + '</strong>';
}
With the following test:
// File: __tests__/foo.test.js
jest.unmock('../index');
import { makeBold, myName } from '../index';
describe('bar()', () => {
it('calls myName', () => {
myName = jest.fn();
makeBold('Text');
expect(myName).toBeCalled();
});
});
The above would throw similar to:
... myName is read-only ...
Jest mocks things on the module boundary, which is the boundary at which you should test your "units" (= modules). With JavaScript, there is no way to swap out references to something.
Consider this example:
// a.js
exports.a = 42;
// b.js
var b = require('./a').a;
b = 14;
console.log(require('./a').a); // still 42
this is a simple example similar to your code that should point out the problem you are having. You cannot swap out a function that is internal to a module. When you try to overwrite myName
with jest.fn()
in your example, you are just modifying the local binding myName
in your test but it has no effect on the myName
binding in your other file. This unfortunately becomes more of a problem with ES2015 modules where it is less obvious. The right solution here is to split up myName
and makeBold
into two separate modules and mock myName
. Generally, there is little value in writing a test like the one you are writing here: you should test that makeBold
_behaves_ as expected, not that its internal implementation relies on any particular implementation details.
One way however to do what you are trying to do is to drop down to CommonJS (which babel compiles to, anyway):
// module.js
exports.foo = function() {};
exports.bar = function() { exports.foo(); }
// test.js
const module = require('./module');
module.foo = jest.fn();
module.bar();
expect(module.foo).toBeCalled();
This works because the bar
function calls foo
with a binding that can be modified – exports.foo
is just a field on an object that can freely be modified.
I hope this explanation makes sense and I provided enough guidance so that you can write a good test. Please note that this is mostly a limitation of ES2015 (modules) and we can't really do much about this. Also, this is a bug tracker that we use to prioritize work. It's not well-suited for questions. In the future, please ask questions on StackOverflow.
you should test that makeBold behaves as expected, not that its internal implementation relies on any particular implementation details.
So true, thats basically what we did in the end.
Apologies for logging an issue, I understand such"questions" are not suited for an issue tracker. Although at times its hard to differ the two.
That's alright! Now we have this documented somewhere, so that's good for the next person who runs into this :)
@danieldiekmeier, could you provide more information how spyOn
could solve raise issue, please?
leave me an answer if it work for es6
Sorry to comment an old issue. Please forgive if it has broken any rules 😅
I was wondering what the test would look like to achieve:
you should test that makeBold behaves as expected, not that its internal implementation relies on any particular implementation details.
Does it mean we directly assert the return value of makeBold
function ? In stead of asserting it has called myName
function ?
To anybody coming here looking for answers like I was, check out babel-plugin-rewire.
Most helpful comment
Jest mocks things on the module boundary, which is the boundary at which you should test your "units" (= modules). With JavaScript, there is no way to swap out references to something.
Consider this example:
this is a simple example similar to your code that should point out the problem you are having. You cannot swap out a function that is internal to a module. When you try to overwrite
myName
withjest.fn()
in your example, you are just modifying the local bindingmyName
in your test but it has no effect on themyName
binding in your other file. This unfortunately becomes more of a problem with ES2015 modules where it is less obvious. The right solution here is to split upmyName
andmakeBold
into two separate modules and mockmyName
. Generally, there is little value in writing a test like the one you are writing here: you should test thatmakeBold
_behaves_ as expected, not that its internal implementation relies on any particular implementation details.One way however to do what you are trying to do is to drop down to CommonJS (which babel compiles to, anyway):
This works because the
bar
function callsfoo
with a binding that can be modified –exports.foo
is just a field on an object that can freely be modified.I hope this explanation makes sense and I provided enough guidance so that you can write a good test. Please note that this is mostly a limitation of ES2015 (modules) and we can't really do much about this. Also, this is a bug tracker that we use to prioritize work. It's not well-suited for questions. In the future, please ask questions on StackOverflow.