用 jest 结合 @testing-library/react 测试 react 组件时,由于组件内部 import 了 css 文件,会抛出如下错误

ca582177-907c-4bf4-8c22-14ab3c245c43.webp
jest unexpectd token

这是由于 jest 默认只识别 js/json文件,对 css/less 等文件,对该文件类型导入没有办法处理。当然不仅仅是 css/less 文件,除上述文件类型之外也是一样的。

解决的办法是使用 jest 的 moduleNameMapper 配置,将 css 文件映射为一个空对象,这样 jest 在处理 css 等不能识别的文件时就不会报错了。

moduleNameMapper

jest 提供了 moduleNameMapper 配置项,可以把模块映射到指定的模块。我们只需要把带有 css/less 等后缀的文件映射到一个空对象即可。

module.exports = {
  moduleNameMapper: {
    '\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
  }
};

接下来在 __mocks__ 目录下新建一个 styleMock.js 文件,内容如下:

module.exports = {};

配置完,再次 pnpm run test 后,即可正常运行单测了。

不过还没完,大部分在开发react组件库的时候,我们使用 css module 的方式来应用样式,用于减少样式命名冲突。然而如果配置成上述的方式,则无法使用 css 选择器来进行查找,因为 jest 在处理 css 变成了一个空对象,所以相当于没有引入样式。

举个例子,我们有一个组件 Button,样式文件 index.module.css,内容如下:

.button {
  background-color: red;
}

在 Button 组件中引入样式文件:

import styles from './index.module.css';
const Button = () => {
  return <button className={styles.button}>Click me</button>;
};
export default Button;

这样在对 Button 组件进行单测时,实际在内存中渲染的 Button 是这样的:

<button className="undefined">Click me</button>

这样就无法通过 css 选择器来查找到对应的元素了。

更优的方案

更优的方案是使用 identity-obj-proxy 这个库,该库会将 css/less 文件映射为一个对象,这样 jest 在处理 css 等文件,会将其转换为一个对象,更方便我们编写单元测试。

在项目中安装 identity-obj-proxy:

pnpm add identity-obj-proxy -D

修改 jest.config.js 配置如下:

module.exports = {
  // ...其他配置
  moduleNameMapper: {
    '\\.(css|less)$': 'identity-obj-proxy'
  }
};

这样配置后,上述的 Button 组件在内存中渲染的 Button 就是这样的:

<button className="button">Click me</button>

最后就可以使用 querySelectorquerySelectorAll 类似的 api 来查找元素。