使用 Jest 模拟 React 组件的依赖

Mock a dependency of a React component using Jest

我有一个 React 组件 (CreateForm)。 React 组件依赖于一个模块(Store)。 CreateForm 有一个取消按钮。单击取消按钮时,应调用 Store 模块的 handleCancel 函数。

我用 Jest 写了一个测试失败:

test.only('should handle cancel button click', () => {
    jest.mock('../../src/store');
    const store = require('../../src/store');
    const wrapper = shallow(<CreateForm />);
    const cancelButton = wrapper.find('button').at(1);
    cancelButton.simulate('click');
    expect(store.default.handleCancel).toBeCalled();
});

测试失败。模拟函数没有被调用,测试失败。反应组件没有得到这个版本的模拟吗?如果是这样,我该如何解决测试?谢谢

我的 CreateForm 组件如下所示:

import Store from './store';

render() {
   return (
     <Panel>
       <FormControls />
       <button onClick={Store.create}>Create</button>
       <button onClick={Store.handleCancel}>Cancel</button>
    </Panel>
  );
}

第二个适合我的即兴测试如下所示。

test.only('should handle cancel button click', () => {
  const store = require('../../src/store').default;
  const cancel = store.handleCancel;
  store.handleCancel = jest.fn();

  const wrapper = shallow(<CreateForm />);
  const cancelButton = wrapper.find('button').at(1);
  cancelButton.simulate('click');
  expect(store.handleCancel).toBeCalled();

  store.handleCancel = cancel;
});

以上测试有效。我正在手动模拟该功能,进行测试并在测试后将功能恢复到原来的状态。有没有更好的方法或 Jest 方法来编写上述测试?谢谢

你忘了告诉 jest 如何模拟商店模块,在你的情况下它只是 undefined

const store = require('../../src/store');
jest.mock('../../src/store', () =>({
 handleCancel: jest.fn()
}));

test.only('should handle cancel button click', () => {
    const wrapper = shallow(<CreateForm />);
    const cancelButton = wrapper.find('button').at(1);
    cancelButton.simulate('click');
    expect(store.default.handleCancel).toBeCalled();//I'm not sure about the default here
});

使用此解决方案,您可以告诉 jest 使用具有 handleCancel 函数的对象来模拟商店,这是一个 jest 间谍。然后你可以在这个间谍上测试它是否被调用。

这就是我使用 Jest 监视导入函数的方法。

导入您正在测试的文件中导入的所有内容。

beforeEach 中模拟它,如果你需要 return 值或其他任何东西,你可以使用更复杂的模拟。

afterEach 中调用 jest.clearAllMocks() 将所有功能重置为正常,以阻止任何模拟落入其他测试。

把它们放在一起看起来像这样。

import shallow from 'enzyme'
import * as Store from './Store' // This should be the actual path from the test file to the import

describe('mocking', () => {
  beforeEach(() => {
    jest.spyOn(Store, 'handleCancel')
    jest.spyOn(Store, 'create')
  })

  afterEach(() => {
    jest.clearAllMocks();
  })

  test.only('should handle cancel button click', () => {
    const wrapper = shallow(<CreateForm />);
    const cancelButton = wrapper.find('button').at(1);
    cancelButton.simulate('click');
    expect(Store.handleCancel).toBeCalled();
  })
})

此外,如果您需要模拟默认导入,您可以这样做。 jest.spyOn(Store, 'default')