首选 identity-obj-proxy,因其将 CSS Modules 类名原样映射为对象键(如 {'btn__primary': 'btn__primary'}),确保 toHaveClass 等断言有效,且零配置、兼容所有样式扩展名;Jest 配置需正确双转义正则,避免因 moduleNameMapper 失效导致测试失败。

直接用 identity-obj-proxy,别写空对象存根。 它比手写 module.exports = {} 更可靠,尤其在 CSS Modules 场景下能保留类名映射,避免测试里 expect(button).toHaveClass('btn__primary') 断言失败。
为什么 identity-obj-proxy 是首选方案
它不是简单返回空对象,而是把导入路径(如 Button.module.css)中的类名原样转成对象键,比如 { 'btn__primary': 'btn__primary' }。这对依赖 CSS Modules 类名做逻辑判断的组件(如根据 styles.primary 渲染不同 class)至关重要。
手写存根(如 styleMock.js)只导出空对象,会导致 import styles from './Button.module.css' 得到 {},后续取 styles.primary 就是 undefined,测试直接报错或漏测。
-
identity-obj-proxy支持所有扩展名:.css、.less、.scss、.sass - 不依赖文件内容解析,零配置、无运行时开销
- 与
@testing-library/react的toHaveClass匹配器天然兼容
moduleNameMapper 配置必须转义点号和括号
正则写错是 Jest 忽略样式 mock 的最常见原因。错误示例:"\.(css|less)$" 看似正确,但实际在 JS 字符串中需双转义——Jest 内部用 new RegExp() 解析,所以反斜杠要写两层。
立即学习“前端免费学习笔记(深入)”;
正确写法(jest.config.js):
module.exports = {
moduleNameMapper: {
'\.(css|less|scss|sass)$': 'identity-obj-proxy'
}
};
如果写在 package.json 的 jest 字段里,JSON 字符串需再加一层转义:
"jest": {
"moduleNameMapper": {
"\\(css|less|scss|sass)$": "identity-obj-proxy"
}
}
- 漏掉开头的
\→ 正则变成字面量匹配,不生效 - 用单引号包裹正则 → 在
package.json中非法,必须用双引号 - 没覆盖
.sass→ 遇到旧项目或遗留配置时测试崩溃
遇到 SyntaxError: Unexpected token 先查 Babel 是否处理了样式文件
Jest 报 .less 文件“意外令牌”,本质是 Babel 尝试编译它——但 Babel 默认不处理 .less。这不是 mock 配置问题,而是加载链路错位。
确认两点:
- Babel 配置里没有
extensions包含.less(例如@babel/preset-env的targets不管这个) - Jest 的
transformIgnorePatterns没把node_modules里带样式的包放行(如某些 UI 库导出.css,需显式忽略) - 真正该处理
.less的是 Jest 的transform或moduleNameMapper,不是 Babel
典型错误配置:
"babel": {
"extensions": ["js", "jsx", "ts", "tsx", "less"] // ❌ 删掉这一行
}
需要真实 CSS 行为时,别硬扛 mock
如果你的测试确实依赖样式计算(比如测 getBoundingClientRect()、伪元素内容、媒体查询响应),identity-obj-proxy 就不合适了。这时候该换方案:
- 用
jest-preview:它在浏览器环境里真实加载并应用 CSS,debug()后可直观验证布局 - 用
jest-css-snapshot:针对 SCSS/Sass 输出做字符串快照,测的是编译结果而非运行时渲染 - 手动注入
<style></style>:在setupFilesAfterEnv里用document.head.appendChild加载已编译的 CSS 文件(仅限极简场景)
mock 的意义是隔离,不是伪造行为。一旦开始绕过 mock 去测样式细节,说明测试目标已经从“组件是否正常挂载”变成了“CSS 是否生效”,该换工具链了。


















