使用 Jest 测试 module.hot

IT技术 javascript reactjs jestjs
2021-04-30 19:13:11

我正在尝试将具有热module重新加载设置的module的覆盖率提高到 100%。

在我的module中,我有这个:

// app.js
if (module && module.hot) module.hot.accept();

在测试文件中,我正在尝试执行此操作

// app.test.js
it('should only call module.hot.accept() if hot is defined', () => {
    const accept = jest.fn();
    global.module = { hot: { accept } };
    jest.resetModules();
    require('./app');
    expect(accept).toHaveBeenCalled();
  }
);

但是当我在 app.js 中注销module时,它显示了需要的东西,但不包含测试设置的热方法。

2个回答

如果您有一个引用module对象的变量,那么您可以将模拟module对象注入该变量以进行测试。例如,您可以执行以下操作:

// app.js

// ...
  moduleHotAccept(module);
// ...

export function moduleHotAccept(mod) {
  if (mod && mod.hot) {
    mod.hot.accept();
  }
}

可以这样测试:

// app.test.js
import { moduleHotAccept } from './app'

it('should only call hot.accept() if hot is defined', () => {
    const accept = jest.fn();
    const mockModule = { hot: { accept } };
    moduleHotAccept(mockModule);
    expect(accept).toHaveBeenCalled();
  }
);

it('should not throw if module is undefined', () => {
    expect(moduleHotAccept).not.toThrow();
  }
);

it('should not throw if module.hot is undefined', () => {
    expect(
      () => moduleHotAccept({notHot: -273})
    ).not.toThrow();
  }
);

我也需要它,但无法从外部传递它。

我的解决方案是使用一个开玩笑的“转换”,它允许我稍微修改使用module.hot.

因此,为了设置它,您需要添加:

// package.json

"transform": {
  "file-to-transform.js": "<rootDir>/preprocessor.js"
//-------^ can be .* to catch all
//------------------------------------^ this is a path to the transformer
},

里面preprocessor.js

// preprocessor.js

module.exports = {
  process(src, path) {
    if( path.includes(... the path of the file that uses module.hot)) {
      return src.replace('module.hot', 'global.module.hot');
    }

    return src;
  },
};

该转换器将替换module.hotglobal.module.hot,这意味着您可以在测试中控制它的值,如下所示:

// some-test.spec.js

global.module = {
  hot: {
    accept: jest.fn,
  },
};

希望它有帮助。