Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing exported modules in the same file #1075

Closed
andrewmclagan opened this issue May 26, 2016 · 8 comments
Closed

Testing exported modules in the same file #1075

andrewmclagan opened this issue May 26, 2016 · 8 comments

Comments

@andrewmclagan
Copy link

andrewmclagan commented May 26, 2016

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 ...

@cpojer
Copy link
Member

cpojer commented May 26, 2016

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.

@cpojer cpojer closed this as completed May 26, 2016
@andrewmclagan
Copy link
Author

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.

@cpojer
Copy link
Member

cpojer commented May 26, 2016

That's alright! Now we have this documented somewhere, so that's good for the next person who runs into this :)

@dankremniov
Copy link

@danieldiekmeier, could you provide more information how spyOn could solve raise issue, please?

@mnosuk

This comment has been minimized.

@Yxwww
Copy link

Yxwww commented Oct 29, 2018

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 ?

jfsiii pushed a commit to jfsiii/kibana that referenced this issue Sep 25, 2020
Deal with issue described in jestjs/jest#1075 (comment)

epm/packages/install has functions a, b, c which are independent but a can also call b and c

function a() {
  b();
  c();
}

The linked FB issue describes the cause and rationale (Jest works on "module" boundary) but TL;DR: it's easier if you split up your files

Some related links I found during this journey

 * https://medium.com/@qjli/how-to-mock-specific-module-function-in-jest-715e39a391f4
  * https://stackoverflow.com/questions/52650367/jestjs-how-to-test-function-being-called-inside-another-function
   * https://stackoverflow.com/questions/50854440/spying-on-an-imported-function-that-calls-another-function-in-jest/50855968#50855968
jonathan-buttner added a commit to elastic/kibana that referenced this issue Sep 28, 2020
* Adding bulk upgrade api

* Addressing comments

* Removing todo

* Changing body field

* Adding helper for getting the bulk install route

* Adding request spec

* Pulling in Johns changes

* Removing test for same package upgraded multiple times

* Adding upgrade to setup route

* Adding setup integration test

* Clean up error handling

* Beginning to add tests

* Failing jest mock tests

* Break up tests & modules for easier testing.

Deal with issue described in jestjs/jest#1075 (comment)

epm/packages/install has functions a, b, c which are independent but a can also call b and c

function a() {
  b();
  c();
}

The linked FB issue describes the cause and rationale (Jest works on "module" boundary) but TL;DR: it's easier if you split up your files

Some related links I found during this journey

 * https://medium.com/@qjli/how-to-mock-specific-module-function-in-jest-715e39a391f4
  * https://stackoverflow.com/questions/52650367/jestjs-how-to-test-function-being-called-inside-another-function
   * https://stackoverflow.com/questions/50854440/spying-on-an-imported-function-that-calls-another-function-in-jest/50855968#50855968

* Add test confirming update error result will throw

* Keep orig error. Add status code in http handler

* Leave error as-is

* Removing accidental code changes. File rename.

* Missed a function when moving to a new file

* Add missing type imports

* Lift .map lambda into named outer function

* Adding additional test

* Fixing type error

Co-authored-by: John Schulz <john.schulz@elastic.co>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
jonathan-buttner added a commit to jonathan-buttner/kibana that referenced this issue Sep 28, 2020
* Adding bulk upgrade api

* Addressing comments

* Removing todo

* Changing body field

* Adding helper for getting the bulk install route

* Adding request spec

* Pulling in Johns changes

* Removing test for same package upgraded multiple times

* Adding upgrade to setup route

* Adding setup integration test

* Clean up error handling

* Beginning to add tests

* Failing jest mock tests

* Break up tests & modules for easier testing.

Deal with issue described in jestjs/jest#1075 (comment)

epm/packages/install has functions a, b, c which are independent but a can also call b and c

function a() {
  b();
  c();
}

The linked FB issue describes the cause and rationale (Jest works on "module" boundary) but TL;DR: it's easier if you split up your files

Some related links I found during this journey

 * https://medium.com/@qjli/how-to-mock-specific-module-function-in-jest-715e39a391f4
  * https://stackoverflow.com/questions/52650367/jestjs-how-to-test-function-being-called-inside-another-function
   * https://stackoverflow.com/questions/50854440/spying-on-an-imported-function-that-calls-another-function-in-jest/50855968#50855968

* Add test confirming update error result will throw

* Keep orig error. Add status code in http handler

* Leave error as-is

* Removing accidental code changes. File rename.

* Missed a function when moving to a new file

* Add missing type imports

* Lift .map lambda into named outer function

* Adding additional test

* Fixing type error

Co-authored-by: John Schulz <john.schulz@elastic.co>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
jonathan-buttner added a commit to elastic/kibana that referenced this issue Sep 28, 2020
* Adding bulk upgrade api

* Addressing comments

* Removing todo

* Changing body field

* Adding helper for getting the bulk install route

* Adding request spec

* Pulling in Johns changes

* Removing test for same package upgraded multiple times

* Adding upgrade to setup route

* Adding setup integration test

* Clean up error handling

* Beginning to add tests

* Failing jest mock tests

* Break up tests & modules for easier testing.

Deal with issue described in jestjs/jest#1075 (comment)

epm/packages/install has functions a, b, c which are independent but a can also call b and c

function a() {
  b();
  c();
}

The linked FB issue describes the cause and rationale (Jest works on "module" boundary) but TL;DR: it's easier if you split up your files

Some related links I found during this journey

 * https://medium.com/@qjli/how-to-mock-specific-module-function-in-jest-715e39a391f4
  * https://stackoverflow.com/questions/52650367/jestjs-how-to-test-function-being-called-inside-another-function
   * https://stackoverflow.com/questions/50854440/spying-on-an-imported-function-that-calls-another-function-in-jest/50855968#50855968

* Add test confirming update error result will throw

* Keep orig error. Add status code in http handler

* Leave error as-is

* Removing accidental code changes. File rename.

* Missed a function when moving to a new file

* Add missing type imports

* Lift .map lambda into named outer function

* Adding additional test

* Fixing type error

Co-authored-by: John Schulz <john.schulz@elastic.co>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

Co-authored-by: John Schulz <john.schulz@elastic.co>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
@lyleunderwood
Copy link

To anybody coming here looking for answers like I was, check out babel-plugin-rewire.

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants