
Next.js 基于 Babel 的 Jest 单元测试配置实战深入解析 with-jest-babel 示例【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js导读with-jest-babel是 Next.js 官方仓库中一套“在测试中走 Babel 转译管线”的 Jest 集成示例用于在 Pages Router 应用中为 React 组件编写单元测试与快照测试同时原生兼容全局 CSS、CSS Modules 和 TypeScript。阅读本文后你将掌握使用create-next-app拉取该示例、读懂jest.config.js中每一项关键配置CSS/图片 Mock、路径别名映射、babel-jest转译等、理解next/babel预设的底层工作方式并能在自己的项目中复刻这套测试环境。为什么还需要一个基于 Babel 的 Jest 示例Jest 要测试 React 组件必须先把 JSX、TypeScript 以及 Next.js 专属语法转译成 Node 可执行的 JavaScript。Next.js 社区中主要有两条技术路线SWC 路线Next.js 12 起内置Next.js 12 开始为 Jest 提供了开箱即用的配置封装即next/jest入口文件其底层由 SWC 完成转译。当前仓库中对应的官方示例是 with-jest其 jest.config.js 通过nextJest({ dir: ./ })一次性完成配置加载是官方推荐的最新实现。Babel 路线本示例通过babel-jest配合next/babel预设转译测试代码next/babel正是 Next.js 在自身构建管线中使用的 Babel 预设。当项目由于依赖自定义 Babel 插件等原因需要使用 Babel 时with-jest-babel 示例便是与之对应的测试配置模板。两条路线在“如何编写测试”上完全一致区别仅在于转译器的选择。本示例还一并演示了 Next.js 对全局 CSS、CSS Modules 与 TypeScript 的内置支持如何在测试环境中被正确处理。快速启动创建示例并运行测试官方提供了基于create-next-app的一键初始化方式三种包管理器任选其一npx create-next-app --example with-jest-babel with-jest-babel-appyarn create next-app --example with-jest-babel with-jest-babel-apppnpm create next-app --example with-jest-babel with-jest-babel-app脚手架初始化完成并安装依赖后进入项目目录即可运行测试npm testyarn testpnpm test测试脚本定义在 package.json 中scripts: { dev: next dev, build: next build, start: next start, test: jest --watch, test:ci: jest --ci }npm test进入jest --watch监视模式适合本地开发时边改边跑test:ci即npm run test:ci以--ci模式运行适合 CI 流水线不进入 watch、不交互匹配到变更即失败退出保证可重复执行。示例项目结构examples/with-jest-babel/ ├── __mocks__/ # 静态资源 Mock │ ├── fileMock.js # 图片等文件导入的桩 │ └── styleMock.js # 非 CSS Modules 样式的桩 ├── __tests__/ │ ├── index.test.tsx # Testing Library 行为测试 │ ├── snapshot.tsx # 快照测试 │ └── __snapshots__/ │ └── snapshot.tsx.snap # 自动生成的快照 ├── pages/ │ ├── _app.tsx # 引入全局 CSS │ ├── index.module.css # CSS Module 样式 │ └── index.tsx # 被测首页组件 ├── public/ # favicon、logo 等静态资源 ├── styles/ │ └── global.css # 全局样式 ├── jest.config.js # Jest 核心配置 ├── jest.setup.js # 测试环境初始化 ├── package.json ├── tsconfig.json # TS 与路径别名配置 └── types.d.ts # 为 *.module.css 补充 TS 类型jest.config.js 配置逐项拆解jest.config.js 是整个示例的心脏逐项说明如下collectCoverageFrom覆盖率采集范围collectCoverageFrom: [ **/*.{js,jsx,ts,tsx}, !**/*.d.ts, !**/node_modules/**, ],声明生成覆盖率报告时要统计哪些文件所有 JS/JSX/TS/TSX 源码但排除类型声明文件与node_modules。注意此配置只是划定“范围”真正采集还需在运行时传入--coverage。moduleNameMapper三类资源的 Mock 与别名映射moduleNameMapper: { // 处理 CSS Modules ^.\\.module\\.(css|sass|scss)$: identity-obj-proxy, // 处理普通 CSS ^.\\.(css|sass|scss)$: rootDir/__mocks__/styleMock.js, // 处理图片导入 ^.\\.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$: rootDir/__mocks__/fileMock.js, // 处理模块别名 ^/components/(.*)$: rootDir/components/$1, ^/pages/(.*)$: rootDir/pages/$1, }以.module.css/.sass/.scss结尾的CSS Modules映射到identity-obj-proxy它在运行时返回一个“把类名原样映射为类名”的对象因此import styles from /pages/index.module.css后styles.container就是字符串containerclassName{styles.container}可被正常断言非 Module 的普通 CSS例如 _app.tsx 中的import /styles/global.css映射到 styleMock.js它只是一个module.exports {}的空对象桩图片、字体等静态资源映射到 fileMock.js返回一个带src/height/width/blurDataURL的桩对象模拟next/image需要的字段最后两组正则把/components/*、/pages/*别名映射回真实目录与 tsconfig.json 中的paths/components/*、/pages/*、/styles/*一一对应保证测试里写的别名导入能被 Jest 解析。顺序很关键Jest 按定义顺序匹配第一个命中的规则因此 CSS Modules 的正则必须写在普通 CSS 之前否则会被更宽泛的第二条规则抢先拦截。setupFilesAfterEnv运行前加载测试框架setupFilesAfterEnv: [rootDir/jest.setup.js],在每个测试文件运行前执行指定脚本。jest.setup.js 的内容是把jest-dom的匹配器注入 Jestimport testing-library/jest-dom/extend-expect;这使得断言可以写成expect(heading).toBeInTheDocument()、toBeVisible()等语义化匹配器。若删除该文件需同步移除setupFilesAfterEnv配置。testPathIgnorePatterns 与 transform转译的收与放testPathIgnorePatterns: [rootDir/node_modules/, rootDir/.next/], transform: { ^.\\.(js|jsx|ts|tsx)$: [babel-jest, { presets: [next/babel] }], },testPathIgnorePatterns明确排除node_modules与.next构建产物目录Jest 不会把这些目录当作测试或被测代码扫描。transform是本示例区别于 SWC 方案的核心凡是.js/.jsx/.ts/.tsx文件都由babel-jest用next/babel预设转译也就是与 Next.js 官方构建时完全一致的 Babel 管线详见下文源码解析。transformIgnorePatternstransformIgnorePatterns: [ /node_modules/, ^.\\.module\\.(css|sass|scss)$, ],node_modules默认不转译以避免体积膨胀第二条规则进一步声明 CSS Modules 文件不经过babel-jest它们本来已由identity-obj-proxy接管无需转译。testEnvironmenttestEnvironment: jest-environment-jsdom,被测组件依赖 DOM API如document、事件因此测试环境指定为 jsdom。依赖中需显式安装jest-environment-jsdom见 package.json。依赖清单解读package.json 的devDependencies展示了这套方案所需的全部测试相关依赖devDependencies: { testing-library/jest-dom: 5.16.4, testing-library/react: 13.2.0, testing-library/user-event: 14.2.0, types/jest: 29.5.5, types/react: 18.2.8, babel-jest: 28.1.0, identity-obj-proxy: 3.0.0, jest: 28.1.0, jest-environment-jsdom: 28.1.0, typescript: 4.6.4 }babel-jest、jest、jest-environment-jsdom三者的主版本号保持一致28.x这是 Jest 生态的一个常见约束升级时三者需同步identity-obj-proxy提供 CSS Modules 的“类名原样返回”代理Testing Library 三件套react、jest-dom、user-event负责以用户视角渲染组件、断言与模拟交互。next/babel 预设的底层实现解析在 jest.config.js 中传入的next/babel并不是一个虚构的预设名它真实存在于本仓库的 Next.js 包中。packages/next/babel.js 入口将其直接指向 Babel 预设实现module.exports require(./dist/build/babel/preset)源码实现位于 packages/next/src/build/babel/preset.ts读懂它有助于理解为什么这套测试配置能“零 Babel 配置文件”直接工作1. 模式探测。预设没有caller上下文时例如被 Jest 直接调用会根据NODE_ENV推断当前模式const isLoadIntentTest process.env.NODE_ENV test // ... const isTest isCallerDevelopment null isLoadIntentTest见 preset.ts 与 preset.ts因此以NODE_ENVtest运行 Jest 时预设自动进入“测试模式”。2. 测试模式下的行为差异。预设内部组合了preset-env、preset-react、preset-typescript及若干插件当用于测试或服务端时若未显式指定targetspreset-env会自动把目标设为当前 Node 版本node: process.versions.node见 preset.ts。Jest 运行在 Node 中这样的目标设置转译产物最精简、执行最快preset-react在测试/开发模式下打开development选项保留 JSX 源码定位信息方便报错排查生产环境专用的plugin-transform-react-remove-prop-types在测试模式下不会启用见 preset.ts测试断言所需的propTypes不会被剥离插件列表还包含styled-jsx测试模式下可通过styled-jsx选项的babel-test切换为styled-jsx/babel-test、react-loadable-plugin、optimize-hook-destructuring等这些正是 Next.js 组件在真实渲染时依赖的转译行为。换句话说这套 Jest 配置让测试代码与构建代码共享同一份 Babel 语义避免了“测试里能跑、页面上报错”的转译不一致问题。编写第一批测试示例提供了两类测试写法均位于tests目录被测对象是 pages/index.tsx 首页组件其 CSS Module 样式见 pages/index.module.css。1. 行为测试Testing Library。tests/index.test.tsximport { render, screen } from testing-library/react; import Home from /pages/index; describe(Home, () { it(renders a heading, () { render(Home /); const heading screen.getByRole(heading, { name: /welcome to next\.js!/i, }); expect(heading).toBeInTheDocument(); }); });要点通过别名/pages/index导入组件验证了moduleNameMapper与tsconfig paths生效用getByRole按可访问性语义定位标题toBeInTheDocument来自 jest.setup.js 注入的jest-dom匹配器。2. 快照测试。tests/snapshot.tsximport { render } from testing-library/react; import Home from /pages/index; it(renders homepage unchanged, () { const { container } render(Home /); expect(container).toMatchSnapshot(); });首次运行时 Jest 会生成快照文件tests/snapshots/snapshot.tsx.snap其中记录了渲染出的 DOM 结构如Welcome to Next.js!标题与导航卡片等。快照中classcontainer等类名以原样字符串出现正是identity-obj-proxy处理 CSS Modules 的结果。此后若组件输出变化导致快照不匹配Jest 会提示你确认是预期变更更新快照还是意外回归。TypeScript 侧的配套声明测试与源码中出现import styles from /pages/index.module.css时TypeScript 需要知道该模块的类型。types.d.ts 提供了全局声明declare module *module.css { const styles: { [className: string]: string; }; export default styles; }同时 tsconfig.json 在include中收录了types.d.ts与全部**/*.ts(x)并把strict: true、jsx: react-jsx等选项与测试场景对齐保证npm run test:ci与next build使用同一套类型心智模型。在 CI 中落地由于npm test默认进入 watch 模式不适合流水线。示例刻意提供了test:ci脚本jest --ci建议在 CI 中执行npm run test:ci此外如需覆盖率统计可在test:ci后追加--coverage配合jest.config.js中预先配置好的collectCoverageFrom范围即可输出对应文件集的覆盖率报告。小结with-jest-babel的核心价值在于它用一套完整可跑的示例证明了“测试也可以复用 Next.js 官方的 Babel 预设”。当你由于自定义 Babel 插件而无法切换到 SWC 的next/jest时请按本示例的模板落地babel-jestnext/babel负责转译moduleNameMapper负责 CSS/图片与别名jest.setup.js注入jest-domjest-environment-jsdom提供 DOM 环境——四个部件各司其职构成一个与构建管线语义一致、可持续演进到 CI 的测试基础设施。对偏好 SWC 默认方案的项目则可直接参考同仓库的 with-jest 示例。【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考