【问题标题】:Unable to spyOn imported function in compose block under componentDidMount无法在 componentDidMount 下的 compose 块中监视导入的函数
【发布时间】:2019-02-16 07:23:37
【问题描述】:

在使用 spyOn 为我的 Reactjs 应用程序使用 recompose、redux 等测试我的 compose() 块内的方法调用时遇到一些问题。

基本布局是这样的:

// index.jsx
import { foo, baz } from './lib';
const enhance = compose(
  foo(),
  lifecycle({
      componentDidMount() {
        baz();
      }
  });
);
export const MyComp = (...);
const mapStateToProps = state => (...);
export connect(mapStateToProps)(enhance(MyComp));

// lib.js
export const foo = () => {
  lifecycle({
      componentDidMount() {
        bar();
      }
  });
}
export const bar = () => {};
export const baz = () => {};

//index.test.jsx
import * as lib from '.libs';

describe('Test', () => {
  const didMountSpy = jest.spyOn(MyComp.prototype, 'componentDidMount');
  const fooSpy = jest.spyOn(lib, 'foo');
  const barSpy = jest.spyOn(lib, 'bar');
  const bazSpy = jest.spyOn(lib, 'baz');

  const wrapper = mount(<MyComp ... />);

  expect(didMountSpy).toHaveBeenCalledTimes(1); // PASS
  expect(bazSpy).toHaveBeenCalledTimes(1); // PASS
  expect(fooSpy).toHaveBeenCalledTimes(1); // FAIL
  expect(barSpy).toHaveBeenCalledTimes(1); // FAIL
});

对我来说奇怪的是,如果您查看 baz(),当函数调用未包含在 compse() 中的另一个方法中时,我能够成功地预期该函数调用。但我无法期待 foo(), bar()。我的怀疑是酶/玩笑如何模拟 Reactjs 生命周期方法有些奇怪。

有没有人遇到过类似的事情并有解决方案让 spyOn 为生命周期.componentDidMount() 下的嵌套方法工作?

谢谢!

【问题讨论】:

    标签: reactjs redux jestjs enzyme recompose


    【解决方案1】:

    fooSpy

    fooSpy 没有被调用,因为fooenhance 被创建时被调用,这发生在index.jsx 被导入时,所以foo 在它被包裹在一个间谍中创建时已经被调用fooSpy.

    如果您想捕获调用了foo,则需要延迟创建enhance

    barSpy

    bar()lib.js 中本地定义,并在foo 的定义中直接调用。

    jest.spyOn 替换了bar模块导出。因为foo的定义是直接使用bar而不是bar的模块导出,所以用spy替换bar的模块导出不会影响foo内的调用,并且永远不会调用barSpy .

    如果您想捕获调用了bar,您需要在foo 的定义中使用bar模块导出


    这是测试的工作版本:

    lib.js

    import { lifecycle } from 'recompose';
    import * as self from './lib';  // import the module into itself
    
    export const foo = () =>
      lifecycle({
          componentDidMount() {
            self.bar();  // call the module export for bar()
          }
      });
    export const bar = () => {};
    export const baz = () => {};
    

    index.jsx

    import * as React from 'react';
    import { compose, lifecycle } from 'recompose';
    
    import { foo, baz } from './lib';
    
    export class MyComp extends React.Component {
      render() { return (<div>My Comp</div>); }
    }
    
    // use a function to delay the creation of enhance()
    export const initialize = () => {
      const enhance = compose(
        foo(),
        lifecycle({
            componentDidMount() {
              baz();
            }
        })
      );
      return enhance(MyComp);
    }
    

    index.test.jsx

    import * as React from 'react';
    import { mount } from 'enzyme';
    
    import * as lib from './lib';
    import { initialize } from './index';
    
    test('MyComp', () => {
      const fooSpy = jest.spyOn(lib, 'foo');
      const barSpy = jest.spyOn(lib, 'bar');
      const bazSpy = jest.spyOn(lib, 'baz');
    
      const MyComp = initialize();  // this will create enhance() which will call foo()
      const didMountSpy = jest.spyOn(MyComp.prototype, 'componentDidMount');
    
      const wrapper = mount(<MyComp />);
    
      expect(didMountSpy).toHaveBeenCalledTimes(1); // PASS
      expect(bazSpy).toHaveBeenCalledTimes(1); // PASS
      expect(fooSpy).toHaveBeenCalledTimes(1); // PASS
      expect(barSpy).toHaveBeenCalledTimes(1); // PASS
    });
    

    【讨论】:

      【解决方案2】:

      你应该使用jest.mock 方法来模拟导入

      按照以下步骤操作:

      • 在 lib.js 所在的同一文件夹中创建一个名为 __mocks__ 的文件夹
      • __mocks__ 文件夹中创建一个名为lib.js 的文件,并为foobarbaz 方法/组件提供一个模拟实现
      • 在 index.test.jsx 中不要导入 lib.js。另外,在 index.test 中导入 index.js 之前,添加以下行

      jest.mock('path-to-lib/lib.js')

      参考:https://jestjs.io/docs/en/manual-mocks

      【讨论】:

        猜你喜欢
        • 2020-12-27
        • 1970-01-01
        • 2018-10-25
        • 2019-01-29
        • 1970-01-01
        • 2018-11-24
        • 1970-01-01
        • 2013-05-05
        相关资源
        最近更新 更多