npx skills add https://github.com/cin12211/orca-q --skill jest-testing-expert我是一位专注于 Jest 测试框架的专家,在配置精通、高级模拟模式、快照测试策略、异步测试模式、自定义匹配器和性能优化方面拥有深厚的知识。
jest.mock() 的模块提升行为jest.useFakeTimers() 和 jest.advanceTimersByTime() 进行计时器控制__mocks__ 目录中的手动模拟广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
问题 : 找不到模块 'jest'
# 根本原因:未安装 Jest 或路径不正确
# 修复 1:安装 Jest
npm install --save-dev jest
# 修复 2:添加到 package.json 的 devDependencies
{
"devDependencies": {
"jest": "^29.0.0"
}
}
# 诊断:npm list jest
# 验证:jest --version
问题 : 找不到 Jest 配置
// ❌ 问题:缺少配置
// ✅ 解决方案:创建 jest.config.js
module.exports = {
testEnvironment: 'node',
collectCoverageFrom: [
'src/**/*.{js,ts}',
'!src/**/*.d.ts'
],
testMatch: ['**/__tests__/**/*.(test|spec).(js|ts)']
};
问题 : SyntaxError: 无法在模块外部使用 import 语句
// ❌ 问题:ESM/CommonJS 不匹配
// ✅ 解决方案 1:在 package.json 中添加 type: "module"
{
"type": "module",
"jest": {
"preset": "ts-jest/presets/default-esm",
"extensionsToTreatAsEsm": [".ts"]
}
}
// ✅ 解决方案 2:配置 babel-jest 转换器
module.exports = {
transform: {
'^.+\\.[jt]sx?$': 'babel-jest',
},
};
问题 : ReferenceError: window 未定义
// ❌ 问题:测试环境错误
// ✅ 解决方案:设置 jsdom 环境
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/src/setupTests.js']
};
// 或者按测试设置环境
/**
* @jest-environment jsdom
*/
问题 : TypeError: regeneratorRuntime 未定义
// ❌ 问题:缺少 async/await polyfill
// ✅ 解决方案:配置 Babel 预设
module.exports = {
presets: [
['@babel/preset-env', {
targets: {
node: 'current'
}
}]
]
};
问题 : TypeScript 文件未被转换
// ❌ 问题:未配置 ts-jest
// ✅ 解决方案:配置 TypeScript 转换
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
};
问题 : 找不到模块(TypeScript 路径)
// ❌ 问题:未配置路径映射
// ✅ 解决方案:添加 moduleNameMapping
module.exports = {
moduleNameMapping: {
'^@/(.*)$': '<rootDir>/src/$1',
'^@components/(.*)$': '<rootDir>/src/components/$1',
'^@utils/(.*)$': '<rootDir>/src/utils/$1'
}
};
问题 : 测试文件中的类型错误
// ❌ 问题:缺少 Jest 类型定义
// ✅ 解决方案:安装 @types/jest
npm install --save-dev @types/jest
// 添加到 tsconfig.json
{
"compilerOptions": {
"types": ["jest", "node"]
}
}
// 使用类型化的 Jest 函数
import { jest } from '@jest/globals';
const mockFn: jest.MockedFunction<typeof originalFunction> = jest.fn();
问题 : 模拟实现未被调用
// ❌ 问题:模拟时序问题
beforeEach(() => {
mockFunction.mockClear(); // 错误的时机
});
// ✅ 解决方案:正确的模拟设置
beforeEach(() => {
jest.clearAllMocks();
mockFunction.mockImplementation(() => 'mocked result');
});
// 验证模拟调用
expect(mockFunction).toHaveBeenCalledWith(expectedArgs);
expect(mockFunction).toHaveBeenCalledTimes(1);
问题 : 模块模拟不工作(提升问题)
// ❌ 问题:导入后模拟
import { userService } from './userService';
jest.mock('./userService'); // 太晚了 - 提升问题
// ✅ 解决方案:在文件顶部模拟
jest.mock('./userService', () => ({
__esModule: true,
default: {
getUser: jest.fn(),
updateUser: jest.fn(),
},
userService: {
getUser: jest.fn(),
updateUser: jest.fn(),
}
}));
问题 : 无法重新定义属性(对象模拟)
// ❌ 问题:不可配置的属性
Object.defineProperty(global, 'fetch', {
value: jest.fn(),
writable: false // 这会导致问题
});
// ✅ 解决方案:正确的属性模拟
Object.defineProperty(global, 'fetch', {
value: jest.fn(),
writable: true,
configurable: true
});
// 或者对现有属性使用 spyOn
const fetchSpy = jest.spyOn(global, 'fetch').mockImplementation();
问题 : 计时器模拟未推进
// ❌ 问题:未配置假计时器
test('delayed function', () => {
setTimeout(() => callback(), 1000);
// 计时器从未推进
});
// ✅ 解决方案:正确的计时器模拟
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
});
test('delayed function', () => {
const callback = jest.fn();
setTimeout(callback, 1000);
jest.advanceTimersByTime(1000);
expect(callback).toHaveBeenCalled();
});
问题 : 异步模拟未解析
// ❌ 问题:错误的 promise 模拟
const mockFn = jest.fn(() => Promise.resolve('result'));
// ✅ 解决方案:使用 mockResolvedValue
const mockFn = jest.fn();
mockFn.mockResolvedValue('result');
// 或者对于拒绝
mockFn.mockRejectedValue(new Error('Failed'));
// 在测试中
await expect(mockFn()).resolves.toBe('result');
await expect(mockFn()).rejects.toThrow('Failed');
问题 : 测试超时
// ❌ 问题:缺少异步处理
test('async operation', () => {
const result = asyncOperation(); // 返回 promise
expect(result).toBe('expected'); // 失败 - result 是 Promise
});
// ✅ 解决方案:正确的异步模式
test('async operation', async () => {
const result = await asyncOperation();
expect(result).toBe('expected');
}, 10000); // 自定义超时
// 或者使用 resolves/rejects
test('async operation', () => {
return expect(asyncOperation()).resolves.toBe('expected');
});
问题 : Promise 拒绝未处理
// ❌ 问题:缺少错误处理
test('error handling', async () => {
const result = await failingOperation(); // 未处理的拒绝
});
// ✅ 解决方案:正确的错误测试
test('error handling', async () => {
await expect(failingOperation()).rejects.toThrow('Expected error');
});
// 或者使用 try/catch
test('error handling', async () => {
try {
await failingOperation();
fail('Should have thrown');
} catch (error) {
expect(error.message).toBe('Expected error');
}
});
问题 : 测试中的竞态条件
// ❌ 问题:时序依赖逻辑
test('race condition', () => {
triggerAsyncOperation();
expect(state).toBe('completed'); // 由于时序问题失败
});
// ✅ 解决方案:使用 waitFor 模式
import { waitFor } from '@testing-library/react';
test('race condition', async () => {
triggerAsyncOperation();
await waitFor(() => {
expect(state).toBe('completed');
});
});
问题 : done() 回调未被调用
// ❌ 问题:缺少 done() 调用
test('callback test', (done) => {
asyncCallback((error, result) => {
expect(result).toBe('success');
// 缺少 done() 调用导致超时
});
});
// ✅ 解决方案:始终调用 done()
test('callback test', (done) => {
asyncCallback((error, result) => {
try {
expect(error).toBeNull();
expect(result).toBe('success');
done();
} catch (testError) {
done(testError);
}
});
});
问题 : 快照测试失败
# ❌ 问题:盲目更新快照
jest --updateSnapshot
# ✅ 解决方案:仔细审查更改
jest --verbose --testNamePattern="snapshot test"
# 在终端中查看差异
# 仅在更改是预期的情况下更新
jest --updateSnapshot --testNamePattern="specific test"
问题 : 无法写入快照
// ❌ 问题:权限问题
// ✅ 解决方案:检查目录权限
const fs = require('fs');
const path = require('path');
beforeAll(() => {
const snapshotDir = path.join(__dirname, '__snapshots__');
if (!fs.existsSync(snapshotDir)) {
fs.mkdirSync(snapshotDir, { recursive: true });
}
});
问题 : 快照序列化器不工作
// ❌ 问题:序列化器未注册
// ✅ 解决方案:添加到 setupFilesAfterEnv
// setupTests.js
expect.addSnapshotSerializer({
test: (val) => val && val.$$typeof === Symbol.for('react.element'),
print: (val, serialize) => serialize(val.props),
});
// 或者在 jest.config.js 中
module.exports = {
snapshotSerializers: ['enzyme-to-json/serializer'],
};
问题 : 快照太大
// ❌ 问题:完整组件快照
expect(wrapper).toMatchSnapshot();
// ✅ 解决方案:使用属性匹配器进行针对性快照
expect(wrapper.find('.important-section')).toMatchSnapshot();
// 或者使用属性匹配器
expect(user).toMatchSnapshot({
id: expect.any(String),
createdAt: expect.any(Date),
});
问题 : 测试运行缓慢
// ❌ 问题:顺序执行
module.exports = {
maxWorkers: 1, // 过于保守
};
// ✅ 解决方案:优化并行化
module.exports = {
maxWorkers: '50%', // 使用一半可用核心
cache: true,
cacheDirectory: '<rootDir>/.jest-cache',
setupFilesAfterEnv: ['<rootDir>/tests/setup.js'],
};
问题 : 内存不足错误
// ❌ 问题:内存泄漏
afterEach(() => {
// 缺少清理
});
// ✅ 解决方案:正确的清理模式
afterEach(() => {
jest.clearAllMocks();
jest.clearAllTimers();
// 如果使用 jsdom,清理 DOM
document.body.innerHTML = '';
});
// 使用内存监控运行
// jest --logHeapUsage --detectLeaks
问题 : Jest 工作进程崩溃
# ❌ 问题:工作进程太多
jest --maxWorkers=8 # 在 4 核机器上
# ✅ 解决方案:调整工作进程数量
jest --maxWorkers=2
# 或者增加 Node.js 内存
NODE_OPTIONS="--max-old-space-size=4096" jest
问题 : 覆盖率报告为空
// ❌ 问题:错误的模式
module.exports = {
collectCoverageFrom: [
'src/**/*.js', // 缺少 TypeScript 文件
],
};
// ✅ 解决方案:全面的模式
module.exports = {
collectCoverageFrom: [
'src/**/*.{js,ts,jsx,tsx}',
'!src/**/*.d.ts',
'!src/**/*.stories.*',
'!src/**/index.{js,ts}',
],
};
问题 : 覆盖率阈值未达到
// ❌ 问题:不切实际的阈值
module.exports = {
coverageThreshold: {
global: {
branches: 100, // 过于严格
functions: 100,
lines: 100,
statements: 100
}
}
};
// ✅ 解决方案:现实的阈值
module.exports = {
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
},
'./src/critical/': {
branches: 95,
functions: 95,
lines: 95,
statements: 95
}
}
};
问题 : 无法调试 Jest 测试
# ❌ 问题:标准执行
jest
# ✅ 解决方案:使用 Chrome DevTools 的调试模式
node --inspect-brk node_modules/.bin/jest --runInBand --no-cache
# 在 Chrome 浏览器中打开 chrome://inspect 进行调试
# 替代方案:使用 console.log 调试
npm test -- --runInBand --verbose 2>&1 | tee test-debug.log
# 分析 test-debug.log 以查找问题
问题 : 仅在 CI 中测试失败
# ❌ 问题:环境差异
# ✅ 解决方案:一致的环境
CI=true NODE_ENV=test jest --ci --coverage --watchAll=false
# 确保一致的 Node.js 版本
node --version # 检查版本一致性
问题 : CI 中的 Jest 缓存问题
# ❌ 问题:陈旧的缓存
# ✅ 解决方案:在 CI 中清除缓存
jest --clearCache
jest --no-cache # 用于 CI 运行
问题 : 并行执行中的不稳定测试
# ❌ 问题:竞态条件
jest --maxWorkers=4
# ✅ 解决方案:用于调试的顺序执行
jest --runInBand --verbose
# 修复根本原因,然后重新启用并行化
// jest.config.js - 生产就绪配置
module.exports = {
// 环境设置
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
// 模块解析
moduleNameMapping: {
'^@/(.*)$': '<rootDir>/src/$1',
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'jest-transform-stub'
},
// 转换器配置
transform: {
'^.+\\.(ts|tsx)$': 'ts-jest',
'^.+\\.(js|jsx)$': 'babel-jest'
},
// 测试模式
testMatch: [
'<rootDir>/src/**/__tests__/**/*.(ts|js)?(x)',
'<rootDir>/src/**/?(*.)(test|spec).(ts|js)?(x)'
],
// 覆盖率配置
collectCoverageFrom: [
'src/**/*.{ts,tsx}',
'!src/**/*.d.ts',
'!src/index.tsx',
'!src/**/*.stories.{ts,tsx}',
'!src/**/__tests__/**',
'!src/**/__mocks__/**'
],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
}
},
coverageReporters: ['text', 'lcov', 'html'],
// 性能优化
maxWorkers: '50%',
cache: true,
cacheDirectory: '<rootDir>/.jest-cache',
// 全局设置
globalSetup: '<rootDir>/tests/globalSetup.js',
globalTeardown: '<rootDir>/tests/globalTeardown.js',
// 监视模式优化
watchPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/build/'],
// 快照配置
snapshotSerializers: ['enzyme-to-json/serializer'],
// 测试超时
testTimeout: 10000,
};
// TypeScript 项目的 jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
globals: {
'ts-jest': {
tsconfig: {
compilerOptions: {
module: 'commonjs',
target: 'es2020',
lib: ['es2020', 'dom'],
skipLibCheck: true,
allowSyntheticDefaultImports: true,
esModuleInterop: true,
moduleResolution: 'node',
resolveJsonModule: true,
isolatedModules: true,
noEmit: true
}
},
isolatedModules: true
}
},
moduleNameMapping: {
'^@/(.*)$': '<rootDir>/src/$1'
}
};
// ESM 项目的 jest.config.js
module.exports = {
preset: 'ts-jest/presets/default-esm',
extensionsToTreatAsEsm: ['.ts'],
globals: {
'ts-jest': {
useESM: true
}
},
moduleNameMapping: {
'^(\\.{1,2}/.*)\\.js$': '$1'
},
transform: {
'^.+\\.tsx?$': ['ts-jest', {
useESM: true
}]
}
};
// 级别 1:监视现有方法
const apiSpy = jest.spyOn(api, 'fetchUser');
// 级别 2:使用受控响应的存根
const mockFetch = jest.fn().mockResolvedValue({ data: mockUser });
// 级别 3:模块级模拟
jest.mock('./userService', () => ({
getUserById: jest.fn(),
updateUser: jest.fn(),
}));
// 级别 4:复杂依赖的手动模拟
// __mocks__/axios.js
export default {
get: jest.fn(() => Promise.resolve({ data: {} })),
post: jest.fn(() => Promise.resolve({ data: {} })),
create: jest.fn(function () {
return this;
})
};
// 基于 Promise 的测试,具有更好的错误消息
test('user creation with detailed assertions', async () => {
const userData = { name: 'John', email: 'john@example.com' };
await expect(createUser(userData)).resolves.toMatchObject({
id: expect.any(String),
name: userData.name,
email: userData.email,
createdAt: expect.any(Date)
});
});
// 并发异步测试
test('concurrent operations', async () => {
const promises = [
createUser({ name: 'User1' }),
createUser({ name: 'User2' }),
createUser({ name: 'User3' })
];
const results = await Promise.all(promises);
expect(results).toHaveLength(3);
expect(results.every(user => user.id)).toBe(true);
});
// setupTests.js - 自定义匹配器
expect.extend({
toBeValidEmail(received) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const pass = emailRegex.test(received);
return {
message: () => `expected ${received} ${pass ? 'not ' : ''}to be a valid email`,
pass
};
},
toHaveBeenCalledWithObjectMatching(received, expected) {
const calls = received.mock.calls;
const pass = calls.some(call =>
call.some(arg =>
typeof arg === 'object' &&
Object.keys(expected).every(key => arg[key] === expected[key])
)
);
return {
message: () => `expected mock to have been called with object matching ${JSON.stringify(expected)}`,
pass
};
}
});
// 测试中的性能基准测试
test('performance test', async () => {
const start = performance.now();
await performExpensiveOperation();
const end = performance.now();
const duration = end - start;
expect(duration).toBeLessThan(1000); // 应在 1 秒内完成
});
// 内存使用测试
test('memory usage test', () => {
const initialMemory = process.memoryUsage().heapUsed;
// 执行不应泄漏内存的操作
for (let i = 0; i < 1000; i++) {
createAndDestroyObject();
}
// 如果可用,强制垃圾回收
if (global.gc) {
global.gc();
}
const finalMemory = process.memoryUsage().heapUsed;
const memoryGrowth = finalMemory - initialMemory;
expect(memoryGrowth).toBeLessThan(1024 * 1024); // 增长小于 1MB
});
# Jest 版本和环境
jest --version
node --version
npm list jest ts-jest @types/jest
# 配置验证
jest --showConfig
jest --listTests
# 内存和性能监控
jest --logHeapUsage --detectLeaks --verbose
# 缓存管理
jest --clearCache
jest --no-cache --runInBand
# 工作进程优化
jest --maxWorkers=1 --runInBand
jest --maxWorkers=50%
# 调试特定测试
jest --testNamePattern="failing test" --verbose --no-cache
jest --testPathPattern="src/components" --verbose
# 使用 Node.js 调试器调试
node --inspect-brk node_modules/.bin/jest --runInBand --no-cache
# 监视模式调试
jest --watch --verbose --no-coverage
# 覆盖率生成
jest --coverage --coverageReporters=text --coverageReporters=html
jest --coverage --collectCoverageFrom="src/critical/**/*.{js,ts}"
# 覆盖率阈值测试
jest --coverage --passWithNoTests
我专注于为您的特定用例优化 Jest 的工作方式,确保快速、可靠的测试,并具有全面的覆盖率和可维护的配置。让我帮助您掌握 Jest 的高级功能并解决复杂的测试挑战。
审查 Jest 测试代码时,请关注:
__mocks__ 目录中的手动模拟得到维护和记录每周安装次数
99
仓库
GitHub 星标数
60
首次出现
2026年1月23日
安全审计
安装于
gemini-cli76
opencode76
cursor75
codex72
github-copilot70
claude-code59
I'm a specialized expert in the Jest testing framework with deep knowledge of configuration mastery, advanced mocking patterns, snapshot testing strategies, async testing patterns, custom matchers, and performance optimization.
jest.mock()jest.useFakeTimers() and jest.advanceTimersByTime()__mocks__ directoriesIssue : Cannot find module 'jest'
# Root Cause: Jest not installed or incorrect path
# Fix 1: Install Jest
npm install --save-dev jest
# Fix 2: Add to package.json devDependencies
{
"devDependencies": {
"jest": "^29.0.0"
}
}
# Diagnostic: npm list jest
# Validation: jest --version
Issue : Jest configuration not found
// ❌ Problematic: Missing configuration
// ✅ Solution: Create jest.config.js
module.exports = {
testEnvironment: 'node',
collectCoverageFrom: [
'src/**/*.{js,ts}',
'!src/**/*.d.ts'
],
testMatch: ['**/__tests__/**/*.(test|spec).(js|ts)']
};
Issue : SyntaxError: Cannot use import statement outside a module
// ❌ Problematic: ESM/CommonJS mismatch
// ✅ Solution 1: Add type: "module" to package.json
{
"type": "module",
"jest": {
"preset": "ts-jest/presets/default-esm",
"extensionsToTreatAsEsm": [".ts"]
}
}
// ✅ Solution 2: Configure babel-jest transformer
module.exports = {
transform: {
'^.+\\.[jt]sx?$': 'babel-jest',
},
};
Issue : ReferenceError: window is not defined
// ❌ Problematic: Wrong test environment
// ✅ Solution: Set jsdom environment
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/src/setupTests.js']
};
// Or per-test environment
/**
* @jest-environment jsdom
*/
Issue : TypeError: regeneratorRuntime is not defined
// ❌ Problematic: Missing async/await polyfill
// ✅ Solution: Configure Babel preset
module.exports = {
presets: [
['@babel/preset-env', {
targets: {
node: 'current'
}
}]
]
};
Issue : TypeScript files not being transformed
// ❌ Problematic: ts-jest not configured
// ✅ Solution: Configure TypeScript transformation
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
};
Issue : Cannot find module (TypeScript paths)
// ❌ Problematic: Path mapping not configured
// ✅ Solution: Add moduleNameMapping
module.exports = {
moduleNameMapping: {
'^@/(.*)$': '<rootDir>/src/$1',
'^@components/(.*)$': '<rootDir>/src/components/$1',
'^@utils/(.*)$': '<rootDir>/src/utils/$1'
}
};
Issue : Type errors in test files
// ❌ Problematic: Missing Jest types
// ✅ Solution: Install @types/jest
npm install --save-dev @types/jest
// Add to tsconfig.json
{
"compilerOptions": {
"types": ["jest", "node"]
}
}
// Use typed Jest functions
import { jest } from '@jest/globals';
const mockFn: jest.MockedFunction<typeof originalFunction> = jest.fn();
Issue : Mock implementation not called
// ❌ Problematic: Mock timing issue
beforeEach(() => {
mockFunction.mockClear(); // Wrong timing
});
// ✅ Solution: Proper mock setup
beforeEach(() => {
jest.clearAllMocks();
mockFunction.mockImplementation(() => 'mocked result');
});
// Verify mock calls
expect(mockFunction).toHaveBeenCalledWith(expectedArgs);
expect(mockFunction).toHaveBeenCalledTimes(1);
Issue : Module mock not working (hoisting problems)
// ❌ Problematic: Mock after import
import { userService } from './userService';
jest.mock('./userService'); // Too late - hoisting issue
// ✅ Solution: Mock at top of file
jest.mock('./userService', () => ({
__esModule: true,
default: {
getUser: jest.fn(),
updateUser: jest.fn(),
},
userService: {
getUser: jest.fn(),
updateUser: jest.fn(),
}
}));
Issue : Cannot redefine property (Object mocking)
// ❌ Problematic: Non-configurable property
Object.defineProperty(global, 'fetch', {
value: jest.fn(),
writable: false // This causes issues
});
// ✅ Solution: Proper property mocking
Object.defineProperty(global, 'fetch', {
value: jest.fn(),
writable: true,
configurable: true
});
// Or use spyOn for existing properties
const fetchSpy = jest.spyOn(global, 'fetch').mockImplementation();
Issue : Timer mocks not advancing
// ❌ Problematic: Fake timers not configured
test('delayed function', () => {
setTimeout(() => callback(), 1000);
// Timer never advances
});
// ✅ Solution: Proper timer mocking
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
});
test('delayed function', () => {
const callback = jest.fn();
setTimeout(callback, 1000);
jest.advanceTimersByTime(1000);
expect(callback).toHaveBeenCalled();
});
Issue : Async mock not resolving
// ❌ Problematic: Incorrect promise mock
const mockFn = jest.fn(() => Promise.resolve('result'));
// ✅ Solution: Use mockResolvedValue
const mockFn = jest.fn();
mockFn.mockResolvedValue('result');
// Or for rejections
mockFn.mockRejectedValue(new Error('Failed'));
// In tests
await expect(mockFn()).resolves.toBe('result');
await expect(mockFn()).rejects.toThrow('Failed');
Issue : Test timeout exceeded
// ❌ Problematic: Missing async handling
test('async operation', () => {
const result = asyncOperation(); // Returns promise
expect(result).toBe('expected'); // Fails - result is Promise
});
// ✅ Solution: Proper async patterns
test('async operation', async () => {
const result = await asyncOperation();
expect(result).toBe('expected');
}, 10000); // Custom timeout
// Or with resolves/rejects
test('async operation', () => {
return expect(asyncOperation()).resolves.toBe('expected');
});
Issue : Promise rejection unhandled
// ❌ Problematic: Missing error handling
test('error handling', async () => {
const result = await failingOperation(); // Unhandled rejection
});
// ✅ Solution: Proper error testing
test('error handling', async () => {
await expect(failingOperation()).rejects.toThrow('Expected error');
});
// Or with try/catch
test('error handling', async () => {
try {
await failingOperation();
fail('Should have thrown');
} catch (error) {
expect(error.message).toBe('Expected error');
}
});
Issue : Race condition in tests
// ❌ Problematic: Timing-dependent logic
test('race condition', () => {
triggerAsyncOperation();
expect(state).toBe('completed'); // Fails due to timing
});
// ✅ Solution: Use waitFor patterns
import { waitFor } from '@testing-library/react';
test('race condition', async () => {
triggerAsyncOperation();
await waitFor(() => {
expect(state).toBe('completed');
});
});
Issue : done() callback not called
// ❌ Problematic: Missing done() call
test('callback test', (done) => {
asyncCallback((error, result) => {
expect(result).toBe('success');
// Missing done() call causes timeout
});
});
// ✅ Solution: Always call done()
test('callback test', (done) => {
asyncCallback((error, result) => {
try {
expect(error).toBeNull();
expect(result).toBe('success');
done();
} catch (testError) {
done(testError);
}
});
});
Issue : Snapshot test failed
# ❌ Problematic: Blindly updating snapshots
jest --updateSnapshot
# ✅ Solution: Review changes carefully
jest --verbose --testNamePattern="snapshot test"
# Review diff in terminal
# Update only if changes are intentional
jest --updateSnapshot --testNamePattern="specific test"
Issue : Cannot write snapshot
// ❌ Problematic: Permission issues
// ✅ Solution: Check directory permissions
const fs = require('fs');
const path = require('path');
beforeAll(() => {
const snapshotDir = path.join(__dirname, '__snapshots__');
if (!fs.existsSync(snapshotDir)) {
fs.mkdirSync(snapshotDir, { recursive: true });
}
});
Issue : Snapshot serializer not working
// ❌ Problematic: Serializer not registered
// ✅ Solution: Add to setupFilesAfterEnv
// setupTests.js
expect.addSnapshotSerializer({
test: (val) => val && val.$$typeof === Symbol.for('react.element'),
print: (val, serialize) => serialize(val.props),
});
// Or in jest.config.js
module.exports = {
snapshotSerializers: ['enzyme-to-json/serializer'],
};
Issue : Snapshot too large
// ❌ Problematic: Full component snapshot
expect(wrapper).toMatchSnapshot();
// ✅ Solution: Targeted snapshots with property matchers
expect(wrapper.find('.important-section')).toMatchSnapshot();
// Or use property matchers
expect(user).toMatchSnapshot({
id: expect.any(String),
createdAt: expect.any(Date),
});
Issue : Tests running slowly
// ❌ Problematic: Sequential execution
module.exports = {
maxWorkers: 1, // Too conservative
};
// ✅ Solution: Optimize parallelization
module.exports = {
maxWorkers: '50%', // Use half of available cores
cache: true,
cacheDirectory: '<rootDir>/.jest-cache',
setupFilesAfterEnv: ['<rootDir>/tests/setup.js'],
};
Issue : Out of memory error
// ❌ Problematic: Memory leaks
afterEach(() => {
// Missing cleanup
});
// ✅ Solution: Proper cleanup patterns
afterEach(() => {
jest.clearAllMocks();
jest.clearAllTimers();
// Clean up DOM if using jsdom
document.body.innerHTML = '';
});
// Run with memory monitoring
// jest --logHeapUsage --detectLeaks
Issue : Jest worker crashed
# ❌ Problematic: Too many workers
jest --maxWorkers=8 # On 4-core machine
# ✅ Solution: Adjust worker count
jest --maxWorkers=2
# Or increase Node.js memory
NODE_OPTIONS="--max-old-space-size=4096" jest
Issue : Coverage report empty
// ❌ Problematic: Wrong patterns
module.exports = {
collectCoverageFrom: [
'src/**/*.js', // Missing TypeScript files
],
};
// ✅ Solution: Comprehensive patterns
module.exports = {
collectCoverageFrom: [
'src/**/*.{js,ts,jsx,tsx}',
'!src/**/*.d.ts',
'!src/**/*.stories.*',
'!src/**/index.{js,ts}',
],
};
Issue : Coverage threshold not met
// ❌ Problematic: Unrealistic thresholds
module.exports = {
coverageThreshold: {
global: {
branches: 100, // Too strict
functions: 100,
lines: 100,
statements: 100
}
}
};
// ✅ Solution: Realistic thresholds
module.exports = {
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
},
'./src/critical/': {
branches: 95,
functions: 95,
lines: 95,
statements: 95
}
}
};
Issue : Cannot debug Jest tests
# ❌ Problematic: Standard execution
jest
# ✅ Solution: Debug mode using Chrome DevTools
node --inspect-brk node_modules/.bin/jest --runInBand --no-cache
# Open chrome://inspect in Chrome browser to debug
# Alternative: Use console.log debugging
npm test -- --runInBand --verbose 2>&1 | tee test-debug.log
# Analyze test-debug.log for issues
Issue : Tests fail only in CI
# ❌ Problematic: Environment differences
# ✅ Solution: Consistent environments
CI=true NODE_ENV=test jest --ci --coverage --watchAll=false
# Ensure consistent Node.js version
node --version # Check version consistency
Issue : Jest cache issues in CI
# ❌ Problematic: Stale cache
# ✅ Solution: Clear cache in CI
jest --clearCache
jest --no-cache # For CI runs
Issue : Flaky tests in parallel execution
# ❌ Problematic: Race conditions
jest --maxWorkers=4
# ✅ Solution: Sequential execution for debugging
jest --runInBand --verbose
# Fix root cause, then re-enable parallelization
// jest.config.js - Production-ready configuration
module.exports = {
// Environment setup
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
// Module resolution
moduleNameMapping: {
'^@/(.*)$': '<rootDir>/src/$1',
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'jest-transform-stub'
},
// Transform configuration
transform: {
'^.+\\.(ts|tsx)$': 'ts-jest',
'^.+\\.(js|jsx)$': 'babel-jest'
},
// Test patterns
testMatch: [
'<rootDir>/src/**/__tests__/**/*.(ts|js)?(x)',
'<rootDir>/src/**/?(*.)(test|spec).(ts|js)?(x)'
],
// Coverage configuration
collectCoverageFrom: [
'src/**/*.{ts,tsx}',
'!src/**/*.d.ts',
'!src/index.tsx',
'!src/**/*.stories.{ts,tsx}',
'!src/**/__tests__/**',
'!src/**/__mocks__/**'
],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
}
},
coverageReporters: ['text', 'lcov', 'html'],
// Performance optimization
maxWorkers: '50%',
cache: true,
cacheDirectory: '<rootDir>/.jest-cache',
// Global setup
globalSetup: '<rootDir>/tests/globalSetup.js',
globalTeardown: '<rootDir>/tests/globalTeardown.js',
// Watch mode optimization
watchPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/build/'],
// Snapshot configuration
snapshotSerializers: ['enzyme-to-json/serializer'],
// Test timeout
testTimeout: 10000,
};
// jest.config.js for TypeScript projects
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
globals: {
'ts-jest': {
tsconfig: {
compilerOptions: {
module: 'commonjs',
target: 'es2020',
lib: ['es2020', 'dom'],
skipLibCheck: true,
allowSyntheticDefaultImports: true,
esModuleInterop: true,
moduleResolution: 'node',
resolveJsonModule: true,
isolatedModules: true,
noEmit: true
}
},
isolatedModules: true
}
},
moduleNameMapping: {
'^@/(.*)$': '<rootDir>/src/$1'
}
};
// jest.config.js for ESM projects
module.exports = {
preset: 'ts-jest/presets/default-esm',
extensionsToTreatAsEsm: ['.ts'],
globals: {
'ts-jest': {
useESM: true
}
},
moduleNameMapping: {
'^(\\.{1,2}/.*)\\.js$': '$1'
},
transform: {
'^.+\\.tsx?$': ['ts-jest', {
useESM: true
}]
}
};
// Level 1: Spy on existing methods
const apiSpy = jest.spyOn(api, 'fetchUser');
// Level 2: Stub with controlled responses
const mockFetch = jest.fn().mockResolvedValue({ data: mockUser });
// Level 3: Module-level mocking
jest.mock('./userService', () => ({
getUserById: jest.fn(),
updateUser: jest.fn(),
}));
// Level 4: Manual mocks for complex dependencies
// __mocks__/axios.js
export default {
get: jest.fn(() => Promise.resolve({ data: {} })),
post: jest.fn(() => Promise.resolve({ data: {} })),
create: jest.fn(function () {
return this;
})
};
// Promise-based testing with better error messages
test('user creation with detailed assertions', async () => {
const userData = { name: 'John', email: 'john@example.com' };
await expect(createUser(userData)).resolves.toMatchObject({
id: expect.any(String),
name: userData.name,
email: userData.email,
createdAt: expect.any(Date)
});
});
// Concurrent async testing
test('concurrent operations', async () => {
const promises = [
createUser({ name: 'User1' }),
createUser({ name: 'User2' }),
createUser({ name: 'User3' })
];
const results = await Promise.all(promises);
expect(results).toHaveLength(3);
expect(results.every(user => user.id)).toBe(true);
});
// setupTests.js - Custom matchers
expect.extend({
toBeValidEmail(received) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const pass = emailRegex.test(received);
return {
message: () => `expected ${received} ${pass ? 'not ' : ''}to be a valid email`,
pass
};
},
toHaveBeenCalledWithObjectMatching(received, expected) {
const calls = received.mock.calls;
const pass = calls.some(call =>
call.some(arg =>
typeof arg === 'object' &&
Object.keys(expected).every(key => arg[key] === expected[key])
)
);
return {
message: () => `expected mock to have been called with object matching ${JSON.stringify(expected)}`,
pass
};
}
});
// Performance benchmarking in tests
test('performance test', async () => {
const start = performance.now();
await performExpensiveOperation();
const end = performance.now();
const duration = end - start;
expect(duration).toBeLessThan(1000); // Should complete in under 1 second
});
// Memory usage testing
test('memory usage test', () => {
const initialMemory = process.memoryUsage().heapUsed;
// Perform operations that should not leak memory
for (let i = 0; i < 1000; i++) {
createAndDestroyObject();
}
// Force garbage collection if available
if (global.gc) {
global.gc();
}
const finalMemory = process.memoryUsage().heapUsed;
const memoryGrowth = finalMemory - initialMemory;
expect(memoryGrowth).toBeLessThan(1024 * 1024); // Less than 1MB growth
});
# Jest version and environment
jest --version
node --version
npm list jest ts-jest @types/jest
# Configuration validation
jest --showConfig
jest --listTests
# Memory and performance monitoring
jest --logHeapUsage --detectLeaks --verbose
# Cache management
jest --clearCache
jest --no-cache --runInBand
# Worker optimization
jest --maxWorkers=1 --runInBand
jest --maxWorkers=50%
# Debug specific tests
jest --testNamePattern="failing test" --verbose --no-cache
jest --testPathPattern="src/components" --verbose
# Debug with Node.js debugger
node --inspect-brk node_modules/.bin/jest --runInBand --no-cache
# Watch mode debugging
jest --watch --verbose --no-coverage
# Coverage generation
jest --coverage --coverageReporters=text --coverageReporters=html
jest --coverage --collectCoverageFrom="src/critical/**/*.{js,ts}"
# Coverage threshold testing
jest --coverage --passWithNoTests
I specialize in making Jest work optimally for your specific use case, ensuring fast, reliable tests with comprehensive coverage and maintainable configuration. Let me help you master Jest's advanced features and resolve complex testing challenges.
When reviewing Jest test code, focus on:
Weekly Installs
99
Repository
GitHub Stars
60
First Seen
Jan 23, 2026
Security Audits
Gen Agent Trust HubFailSocketPassSnykPass
Installed on
gemini-cli76
opencode76
cursor75
codex72
github-copilot70
claude-code59
Vue 3 调试指南:解决响应式、计算属性与监听器常见错误
11,900 周安装
iOS应用本地化指南:Xcode字符串目录、SwiftUI/UIKit国际化与RTL支持
159 周安装
iOS Auto Layout 调试指南:快速解决约束冲突与布局错误
160 周安装
依赖审计完整指南:安全漏洞扫描、过时包检测与清理工作流
164 周安装
iOS Apple Intelligence 路由器使用指南 - Foundation Models 与 AI 方法分流
160 周安装
Agent Skills Creator 指南:创建遵循开放格式的AI技能,涵盖模式选择到验证
164 周安装
gentle-teaching 温和教学框架:AI辅助学习指南,培养独立解决问题能力
161 周安装