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

Ria*_*Ria 22 unit-testing reactjs jestjs babeljs

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

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

我有一个简单的组件Vocabulary,它VocabularyEntry从a 获取-Objects 列表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
 }
 }
Run Code Online (Sandbox Code Playgroud)

vocabularyServise很简单:

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

  class VocabularyService {

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

现在我想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

});
Run Code Online (Sandbox Code Playgroud)

});

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

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

任何人都可以解释我如何解决这个问题?我看到了需要引用的解决方案才能使用模拟调用,但我不明白如何使用类文件执行此操作.

Mis*_*lin 19

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

在这里找到了这个 -  https://github.com/facebook/jest/commit/6a8c7fb874790ded06f4790fdb33d8416a7284c8


And*_*rle 12

问题是所有都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")]
}))
Run Code Online (Sandbox Code Playgroud)

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

  • 这根本行不通。将“jest.mock”移动到“beforeAll”会产生相同的错误,而使用“mockImplementation”会产生“TypeError:mockedModule.mockedFunction不是函数”。 (4认同)
  • 当我这样做时,我得到“myService.mockImplementation 不是一个函数”。 (3认同)

thi*_*ign 9

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

  return {
    vocabulary: [new VocabularyEntry("a", "a1")]
  };
});
Run Code Online (Sandbox Code Playgroud)

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


max*_*tou 8

这就是我为您的代码解决的方式。

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

注意:这是防止未初始化的模拟变量的预防措施。如果确保懒惰地需要该模拟,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

});
Run Code Online (Sandbox Code Playgroud)

  • 这会产生错误:“初始化之前无法访问‘mockVocabulary’” (47认同)
  • 这应该是答案 (4认同)

Mar*_*ten 5

jest.fn()在使用 模拟的模块中实现 a 时jest.mock,请确保执行以下两个步骤:

\n
    \n
  1. 变量名称应以mock.
  2. \n
  3. 如果您写了类似的内容coolFunction: mockCoolFunction,请务必将其更改为coolFunction: (...args) => mockCoolFunction(...args). 这样,Jest 就不需要知道 xe2\x80\x99mockCoolFunction是什么,只要你还没有运行该函数。
  4. \n
\n

如需了解更多信息,我推荐这篇博文

\n