最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How do you manually mock one of your own files in Jest? - Stack Overflow

programmeradmin2浏览0评论

I'm trying to mock an object (which I created) in Jest so I can provide default behaviour within the react component (so the real implementation isn't used)

This is my react component ChatApp (it's very straight forward)

'use strict';
var React, ChatApp, ChatPanel, i18n;

React = require('react');
ChatPanel = require('./chat_panel');
i18n = require('../support/i18n');

ChatApp = React.createClass({
  render() {
    return (
      <div className="chat-app">
        <h1>{i18n.t("app.title")}</h1>
        <ChatPanel />
      </div>
    );
  }
});

module.exports = ChatApp;

So I have a custom I18n dependency that does translations (I18n is something I've written that is a wrapper for node-polyglot).

So I want to do a basic test to see if the H1 has the correct word in it, but I don't want to set jest.dontMock() on my I18n object, because I don't want it to use the real object in the ChatApp test.

So following the basic instructions on the jest website, I created a mocks folder and created a mock file for i18n, which generates a mock from the original object and then overrides the t method and adds a method to allow me to set the return string for t.

This is the mock object

'use strict';
var i18nMock, _returnString;

i18nMock = jest.genMockFromModule('../scripts/support/i18n');

_returnString = "";

function __setReturnString(string) {
  _returnString = string;
}

function t(key, options = null) {
  return _returnString;
}

i18nMock.t.mockImplementation(t);
i18nMock.__setReturnString = __setReturnString;

module.exports = i18nMock;

Now in my ChatApp test I require the mock in a before each, like so:

'use strict';
var React, ChatApp, TestUtils, path;

path = '../../../scripts/components/';
jest.dontMock( path + 'chat_app');

React = require('react/addons');
ChatApp = require( path + 'chat_app');
TestUtils = React.addons.TestUtils;

describe('ChatApp', () => {
  beforeEach(() => {
    require('i18n').__setReturnString('Chat App');
  });

  var ChatAppElement = TestUtils.renderIntoDocument(<ChatApp />);

  it('renders a title on the page', () => {
    var title = TestUtils.findRenderedDOMComponentWithTag(ChatAppElement, 'h1');
    expect(title.tagName).toEqual('H1');
    expect(title.props.children).toEqual('Chat App');
  });
});

If i console.log the i18n object within the test then I get the correct mocked object, the __setReturnString also gets triggered (as if I console.log in that message I see the log).

However, if I console.log the i18n object within the actual React component then it gets a Jest mock but it doesn't get my Jest mock, so the t method is an empty method that doesn't do anything, meaning the test fails.

Any ideas what I'm doing wrong?

Thanks a lot

I'm trying to mock an object (which I created) in Jest so I can provide default behaviour within the react component (so the real implementation isn't used)

This is my react component ChatApp (it's very straight forward)

'use strict';
var React, ChatApp, ChatPanel, i18n;

React = require('react');
ChatPanel = require('./chat_panel');
i18n = require('../support/i18n');

ChatApp = React.createClass({
  render() {
    return (
      <div className="chat-app">
        <h1>{i18n.t("app.title")}</h1>
        <ChatPanel />
      </div>
    );
  }
});

module.exports = ChatApp;

So I have a custom I18n dependency that does translations (I18n is something I've written that is a wrapper for node-polyglot).

So I want to do a basic test to see if the H1 has the correct word in it, but I don't want to set jest.dontMock() on my I18n object, because I don't want it to use the real object in the ChatApp test.

So following the basic instructions on the jest website, I created a mocks folder and created a mock file for i18n, which generates a mock from the original object and then overrides the t method and adds a method to allow me to set the return string for t.

This is the mock object

'use strict';
var i18nMock, _returnString;

i18nMock = jest.genMockFromModule('../scripts/support/i18n');

_returnString = "";

function __setReturnString(string) {
  _returnString = string;
}

function t(key, options = null) {
  return _returnString;
}

i18nMock.t.mockImplementation(t);
i18nMock.__setReturnString = __setReturnString;

module.exports = i18nMock;

Now in my ChatApp test I require the mock in a before each, like so:

'use strict';
var React, ChatApp, TestUtils, path;

path = '../../../scripts/components/';
jest.dontMock( path + 'chat_app');

React = require('react/addons');
ChatApp = require( path + 'chat_app');
TestUtils = React.addons.TestUtils;

describe('ChatApp', () => {
  beforeEach(() => {
    require('i18n').__setReturnString('Chat App');
  });

  var ChatAppElement = TestUtils.renderIntoDocument(<ChatApp />);

  it('renders a title on the page', () => {
    var title = TestUtils.findRenderedDOMComponentWithTag(ChatAppElement, 'h1');
    expect(title.tagName).toEqual('H1');
    expect(title.props.children).toEqual('Chat App');
  });
});

If i console.log the i18n object within the test then I get the correct mocked object, the __setReturnString also gets triggered (as if I console.log in that message I see the log).

However, if I console.log the i18n object within the actual React component then it gets a Jest mock but it doesn't get my Jest mock, so the t method is an empty method that doesn't do anything, meaning the test fails.

Any ideas what I'm doing wrong?

Thanks a lot

Share Improve this question edited Feb 18, 2015 at 15:17 Cihan Keser 3,2615 gold badges31 silver badges43 bronze badges asked Feb 14, 2015 at 10:54 TheStoneFoxTheStoneFox 3,0673 gold badges32 silver badges48 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 8

I've had trouble getting the __mocks__ folder working as well. The way I got around it is by using the jest.setMock(); method.

In your case, you would jest.setMock('../../../scripts/i18n/', require('../__mocks__/i18n');

Obviously, I am not certain of the location of your mock and the location of the real library you're using, but the first parameter should use the path where your real module is stored and the second should use the path where your mock is stored.

This should force your module and all modules that yours require (including React) to use your manually mocked i18n module.

Jest does automatic mocking. Just i18n = require('../support/i18n') should be enough. That's why you usually have to call jest.dontMock in the first place.

You can find more information here: https://facebook.github.io/jest/docs/automatic-mocking.html

What mattykuzyk mentions in his answer did not work at all for me :(

However, what I found out seemed to be the problem for me was the setup of jest: I used moduleNameMapper in the beginning, and for some reason these are never mocked...

So for me the first step was to instead move my module name mapped folder to the moduleDirectories to get anything to work.

After that, I could simply add a __mocks__ file adjacent to the actual implementation (in my case utils/translation.js and utils/__mocks__/translation.js). As my translations.js default exports a translation function, I also default exported my mock. The entire __mocks__/translations.js is super simply and looks like this:

export default jest.fn((key, unwrap = false) => (
    unwrap && `${key}-unwrapped` || `${key}-wrapped`
))

Although I haven't tested it, adding a __setReturnString should be easy enough, for me it was sufficient to actually return my translation key. Hope this helps!

发布评论

评论列表(0)

  1. 暂无评论