用Jest模拟的服务导致“jest.mock()的模块工厂不允许引用任何超出范围的变量”错误

时间:2017-06-20 09:51:57

标签: unit-testing reactjs babeljs jestjs

我正在尝试模拟对服务的调用,但我正在使用以下消息: jest.mock()的模块工厂不允许引用任何超出范围的变量

我正在使用带有ES6语法,开玩笑和酶的babel。

我有一个名为Vocabulary的简单组件,它获取VocabularyEntry的列表 - 来自vocabularyService的对象并呈现它。

import React from 'react';
import vocabularyService from '../services/vocabularyService';

export default class Vocabulary extends React.Component {

render() {

    let rows = vocabularyService.vocabulary.map((v, i) => <tr key={i}>
            <td>{v.src}</td>
            <td>{v.target}</td>
        </tr>
    );
    // render rows
 }
 }

vocabularyServise非常简单:

  import {VocabularyEntry} from '../model/VocabularyEntry';

  class VocabularyService {

  constructor() {
       this.vocabulary = [new VocabularyEntry("a", "b")];
  }
} 
export default new VocabularyService();`

现在我想在测试中模拟vocabularyService

import {shallow} from 'enzyme';
import React from 'react';
import Vocabulary from "../../../src/components/Vocabulary ";
import {VocabularyEntry} from '../../../src/model/VocabularyEntry'

jest.mock('../../../src/services/vocabularyService', () => ({

vocabulary: [new VocabularyEntry("a", "a1")]

}));

describe("Vocabulary tests", () => {

test("renders the vocabulary", () => {

    let $component = shallow(<Vocabulary/>);

    // expect something

});

});

运行测试会导致错误:Vocabulary.spec.js:babel-plugin-jest-hoist:jest.mock()的模块工厂不允许引用任何超出范围的变量。 变量访问无效:VocabularyEntry。

据我所知,我不能使用VocabularyEntry,因为它没有声明(因为jest将模拟定义移动到文件的顶部)。

任何人都可以解释我如何解决这个问题?我看到了需要引用的解决方案,但是我不知道如何使用类文件来执行此操作。

5 个答案:

答案 0 :(得分:16)

如果您在升级到较新的Jest时出现类似错误[在我的情况下为19到21],您可以尝试将jest.mock更改为jest.doMock

在此处找到 - https://github.com/facebook/jest/commit/6a8c7fb874790ded06f4790fdb33d8416a7284c8

答案 1 :(得分:9)

问题是所有jest.mock将在编译时被提升到实际代码块的顶部,在本例中是文件的顶部。此时VocabularyEntry未导入。您可以将mock放在测试中的beforeAll块中,也可以像这样使用jest.mock

import {shallow} from 'enzyme';
import React from 'react';
import Vocabulary from "../../../src/components/Vocabulary ";
import {VocabularyEntry} from '../../../src/model/VocabularyEntry'
import vocabularyService from '../../../src/services/vocabularyService'

jest.mock('../../../src/services/vocabularyService', () => jest.fn)

vocabularyService.mockImplementation(() => ({
  vocabulary: [new VocabularyEntry("a", "a1")]
}))

这将首先使用一个简单的间谍模拟模块,并在导入所有内容后设置模拟的真实实现。

答案 2 :(得分:2)

这就是我为你的代码解决它的方法。

您需要将模拟的组件存储在名为前缀为&#34; mock&#34;的变量中。 此解决方案基于我收到的错误消息末尾的注释。

  

注意:这是防范未初始化模拟的预防措施   变量。如果确保模拟是懒惰的,可变的   允许使用前缀为mock的名称。

import {shallow} from 'enzyme';
import React from 'react';
import Vocabulary from "../../../src/components/Vocabulary ";
import {VocabularyEntry} from '../../../src/model/VocabularyEntry'

const mockVocabulary = () => new VocabularyEntry("a", "a1");

jest.mock('../../../src/services/vocabularyService', () => ({
    default: mockVocabulary
}));

describe("Vocabulary tests", () => {

test("renders the vocabulary", () => {

    let $component = shallow(<Vocabulary/>);

    // expect something

});

答案 3 :(得分:1)

jest.mock("../../../src/services/vocabularyService", () => {
  // eslint-disable-next-line global-require
  const VocabularyEntry = require("../../../src/model/VocabularyEntry");

  return {
    vocabulary: [new VocabularyEntry("a", "a1")]
  };
});

我认为它也应该与动态导入一起使用,而不是require,但无法使其正常工作。

答案 4 :(得分:0)

对于我来说,这个问题是在我使用react-native-git-upgrade将react-native项目升级到v0.61之后开始的。

尽我所能之后。我决定清理项目并将所有测试恢复工作。

# react-native-clean-project

但是在运行react-native-clean-project时要当心,它可以清除所有ios和android文件夹(包括本机代码),因此在提示时仅回答N。就我而言,我只是选择了擦拭node_modules文件夹。