Jest 高级配置 #
配置文件详解 #
配置文件优先级 #
Jest 按以下顺序查找配置文件:
text
1. --config <path> 命令行参数
2. package.json 中的 "jest" 字段
3. jest.config.js
4. jest.config.ts
5. jest.config.json
6. jest.config.mjs
完整配置示例 #
javascript
// jest.config.js
module.exports = {
// 基本配置
rootDir: './src',
testEnvironment: 'jsdom',
// 测试匹配
testMatch: [
'**/__tests__/**/*.[jt]s?(x)',
'**/?(*.)+(spec|test).[jt]s?(x)',
],
testPathIgnorePatterns: [
'/node_modules/',
'/dist/',
],
// 模块配置
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/$1',
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
},
moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx'],
// 转换配置
transform: {
'^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['@babel/preset-env'] }],
},
transformIgnorePatterns: [
'/node_modules/',
],
// 设置文件
setupFiles: ['<rootDir>/jest.env.js'],
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
// 覆盖率配置
collectCoverage: true,
coverageDirectory: 'coverage',
collectCoverageFrom: [
'**/*.{js,jsx,ts,tsx}',
'!**/*.d.ts',
'!**/node_modules/**',
],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
},
},
// 性能配置
maxWorkers: '50%',
cacheDirectory: '/tmp/jest_cache',
// 其他配置
verbose: true,
testTimeout: 5000,
detectOpenHandles: true,
};
预设配置 #
使用预设 #
javascript
// 使用 ts-jest 预设
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
};
// 使用 React 预设
module.exports = {
preset: 'react-scripts',
};
// 使用 Vue 预设
module.exports = {
preset: '@vue/cli-plugin-unit-jest',
};
自定义预设 #
javascript
// my-jest-preset/index.js
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['./setup.js'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
};
// 使用自定义预设
module.exports = {
preset: 'my-jest-preset',
};
全局设置 #
globalSetup #
在所有测试之前执行一次:
javascript
// globalSetup.js
module.exports = async () => {
// 启动测试数据库
await startTestDatabase();
// 设置全局变量
global.__TEST_DB__ = testDb;
console.log('Global setup complete');
};
// jest.config.js
module.exports = {
globalSetup: './globalSetup.js',
};
globalTeardown #
在所有测试之后执行一次:
javascript
// globalTeardown.js
module.exports = async () => {
// 关闭测试数据库
await global.__TEST_DB__.close();
console.log('Global teardown complete');
};
// jest.config.js
module.exports = {
globalTeardown: './globalTeardown.js',
};
组合使用 #
javascript
// jest.config.js
module.exports = {
globalSetup: './globalSetup.js',
globalTeardown: './globalTeardown.js',
};
// globalSetup.js
module.exports = async () => {
const server = await startServer();
return async () => {
await server.close();
};
};
测试环境 #
自定义测试环境 #
javascript
// customEnvironment.js
const TestEnvironment = require('jest-environment-node');
class CustomEnvironment extends TestEnvironment {
constructor(config, context) {
super(config, context);
this.testPath = context.testPath;
}
async setup() {
await super.setup();
// 自定义设置
this.global.myCustomGlobal = 'test value';
}
async teardown() {
// 自定义清理
await super.teardown();
}
getVmContext() {
return super.getVmContext();
}
}
module.exports = CustomEnvironment;
// jest.config.js
module.exports = {
testEnvironment: './customEnvironment.js',
};
jsdom 环境配置 #
javascript
module.exports = {
testEnvironment: 'jsdom',
testEnvironmentOptions: {
html: '<html><body><div id="root"></div></body></html>',
url: 'https://example.com',
userAgent: 'Mozilla/5.0',
runScripts: 'dangerously',
resources: 'usable',
},
};
多项目配置 #
项目配置 #
javascript
// jest.config.js
module.exports = {
projects: [
{
displayName: 'client',
testEnvironment: 'jsdom',
testMatch: ['<rootDir>/client/**/*.test.js'],
},
{
displayName: 'server',
testEnvironment: 'node',
testMatch: ['<rootDir>/server/**/*.test.js'],
},
{
displayName: 'shared',
testEnvironment: 'node',
testMatch: ['<rootDir>/shared/**/*.test.js'],
},
],
};
运行特定项目 #
bash
# 运行所有项目
jest
# 运行特定项目
jest --selectProjects client server
# 忽略特定项目
jest --ignoreProjects shared
自定义匹配器 #
创建自定义匹配器 #
javascript
// matchers.js
expect.extend({
toBeWithinRange(received, floor, ceiling) {
const pass = received >= floor && received <= ceiling;
if (pass) {
return {
message: () => `expected ${received} not to be within range ${floor} - ${ceiling}`,
pass: true,
};
} else {
return {
message: () => `expected ${received} to be within range ${floor} - ${ceiling}`,
pass: false,
};
}
},
toBeValidEmail(received) {
const pass = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(received);
return {
pass,
message: () => pass
? `expected ${received} not to be a valid email`
: `expected ${received} to be a valid email`,
};
},
});
// jest.setup.js
import './matchers';
// 使用
test('custom matchers', () => {
expect(5).toBeWithinRange(1, 10);
expect('test@example.com').toBeValidEmail();
});
TypeScript 支持 #
typescript
// matchers.d.ts
declare global {
namespace jest {
interface Matchers<R> {
toBeWithinRange(floor: number, ceiling: number): R;
toBeValidEmail(): R;
}
}
}
export {};
模块路径映射 #
复杂映射 #
javascript
module.exports = {
moduleNameMapper: {
// 简单映射
'^@/(.*)$': '<rootDir>/src/$1',
// 多个目录映射
'^@components/(.*)$': '<rootDir>/src/components/$1',
'^@utils/(.*)$': '<rootDir>/src/utils/$1',
'^@services/(.*)$': '<rootDir>/src/services/$1',
// 静态资源映射
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
'\\.(jpg|jpeg|png|gif|svg)$': '<rootDir>/__mocks__/fileMock.js',
// 条件映射
'^lodash$': 'lodash-es',
},
};
转换配置 #
多种文件类型转换 #
javascript
module.exports = {
transform: {
// JavaScript/TypeScript
'^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
// Vue 组件
'^.+\\.vue$': '@vue/vue3-jest',
// CSS Modules
'^.+\\.module\\.(css|sass|scss)$': 'jest-css-modules-transform',
// GraphQL
'\\.(gql|graphql)$': 'jest-transform-graphql',
},
};
忽略转换 #
javascript
module.exports = {
transformIgnorePatterns: [
'/node_modules/(?!(@myorg|lodash-es)/)',
],
};
测试隔离 #
每个测试独立进程 #
javascript
module.exports = {
// 每个测试文件在独立进程中运行
runner: 'jest-runner',
// 每个测试独立 VM
testRunner: 'jest-circus/runner',
};
快照配置 #
javascript
module.exports = {
// 快照序列化器
snapshotSerializers: [
'enzyme-to-json/serializer',
'my-custom-serializer',
],
// 快照格式
snapshotFormat: {
escapeString: true,
printBasicPrototype: true,
},
};
监视模式配置 #
javascript
module.exports = {
// 监视模式插件
watchPlugins: [
'jest-watch-typeahead/filename',
'jest-watch-typeahead/testname',
'jest-watch-select-projects',
],
// 监视忽略模式
watchPathIgnorePatterns: [
'/node_modules/',
'/dist/',
],
};
报告器配置 #
自定义报告器 #
javascript
// customReporter.js
class CustomReporter {
constructor(globalConfig, options) {
this._globalConfig = globalConfig;
this._options = options;
}
onRunComplete(contexts, results) {
console.log('Custom reporter output:');
console.log(`Total tests: ${results.numTotalTests}`);
console.log(`Passed: ${results.numPassedTests}`);
console.log(`Failed: ${results.numFailedTests}`);
}
}
module.exports = CustomReporter;
// jest.config.js
module.exports = {
reporters: [
'default',
['./customReporter.js', { option: 'value' }],
],
};
性能优化配置 #
javascript
module.exports = {
// 最大工作进程数
maxWorkers: '50%',
// 缓存目录
cacheDirectory: '/tmp/jest_cache',
// 启用缓存
cache: true,
// 快速失败
bail: 1,
// 测试超时
testTimeout: 5000,
// 并行执行
maxConcurrency: 5,
};
最佳实践 #
1. 分离配置 #
javascript
// jest.config.base.js
module.exports = {
testEnvironment: 'jsdom',
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
};
// jest.config.js
const baseConfig = require('./jest.config.base');
module.exports = {
...baseConfig,
// 特定配置
};
2. 环境变量 #
javascript
// jest.config.js
module.exports = {
testEnvironment: process.env.TEST_ENV || 'jsdom',
maxWorkers: process.env.CI ? 2 : '50%',
};
3. 条件配置 #
javascript
// jest.config.js
const isCI = process.env.CI === 'true';
module.exports = {
cache: !isCI,
coverage: isCI,
maxWorkers: isCI ? 2 : '50%',
};
下一步 #
现在你已经掌握了 Jest 高级配置,接下来学习 性能优化 提升测试效率!
最后更新:2026-03-28