Enzyme 安装与配置 #

安装 Enzyme #

基本安装 #

Enzyme 需要配合测试框架(如 Jest)一起使用:

bash
# 安装 Enzyme 核心包
npm install --save-dev enzyme

# 安装 React 适配器(根据 React 版本选择)
# React 16
npm install --save-dev enzyme-adapter-react-16

# React 16.8+(支持 Hooks)
npm install --save-dev enzyme-adapter-react-16.3

# React 17(非官方适配器)
npm install --save-dev @wojtekmaj/enzyme-adapter-react-17

# React 18(非官方适配器)
npm install --save-dev @cfaester/enzyme-adapter-react-18

完整安装示例 #

bash
# 创建新项目
npx create-react-app my-app
cd my-app

# 安装 Enzyme 和适配器
npm install --save-dev enzyme @wojtekmaj/enzyme-adapter-react-17

# 安装 Jest(如果尚未安装)
npm install --save-dev jest

适配器配置 #

为什么需要适配器? #

text
┌─────────────────────────────────────────────────────────────┐
│                    Enzyme 架构                               │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────────────────────────────────────────────┐   │
│  │                   Enzyme 核心                        │   │
│  │  • 统一的测试 API                                    │   │
│  │  • 选择器引擎                                        │   │
│  │  • 遍历和操作方法                                    │   │
│  └─────────────────────────────────────────────────────┘   │
│                          ↕                                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                   适配器层                           │   │
│  │  • 适配不同版本的 React                              │   │
│  │  • 处理版本差异                                      │   │
│  └─────────────────────────────────────────────────────┘   │
│                          ↕                                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                   React 版本                         │   │
│  │  React 16 / React 17 / React 18                     │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

配置方式 #

方式一:在测试文件中配置 #

javascript
// setupTests.js
import Enzyme from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';

Enzyme.configure({ adapter: new Adapter() });

方式二:在 Jest 配置中引入 #

javascript
// jest.config.js
module.exports = {
  setupFilesAfterEnv: ['<rootDir>/src/setupTests.js'],
};

方式三:在 package.json 中配置 #

json
{
  "jest": {
    "setupFilesAfterEnv": ["<rootDir>/src/setupTests.js"]
  }
}

完整配置示例 #

项目结构 #

text
my-project/
├── src/
│   ├── components/
│   │   ├── Button.js
│   │   └── Button.test.js
│   ├── setupTests.js
│   └── index.js
├── jest.config.js
└── package.json

配置文件 #

package.json #

json
{
  "name": "my-project",
  "version": "1.0.0",
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  },
  "devDependencies": {
    "@wojtekmaj/enzyme-adapter-react-17": "^0.6.0",
    "enzyme": "^3.11.0",
    "jest": "^27.0.0"
  },
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  }
}

jest.config.js #

javascript
module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/src/setupTests.js'],
  moduleNameMapper: {
    '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
    '\\.(jpg|jpeg|png|gif|svg)$': '<rootDir>/__mocks__/fileMock.js'
  },
  testMatch: [
    '**/__tests__/**/*.js',
    '**/*.test.js'
  ],
  collectCoverageFrom: [
    'src/**/*.{js,jsx}',
    '!src/index.js',
    '!src/setupTests.js'
  ]
};

setupTests.js #

javascript
import Enzyme from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';

Enzyme.configure({ adapter: new Adapter() });

// 全局配置
global.console = {
  ...console,
  error: jest.fn(),
  warn: jest.fn()
};

不同 React 版本的配置 #

React 16 配置 #

bash
npm install --save-dev enzyme enzyme-adapter-react-16
javascript
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Enzyme.configure({ adapter: new Adapter() });

React 16.8+ 配置(支持 Hooks) #

bash
npm install --save-dev enzyme enzyme-adapter-react-16.3
javascript
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16.3';

Enzyme.configure({ adapter: new Adapter() });

React 17 配置 #

bash
npm install --save-dev enzyme @wojtekmaj/enzyme-adapter-react-17
javascript
import Enzyme from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';

Enzyme.configure({ adapter: new Adapter() });

React 18 配置 #

bash
npm install --save-dev enzyme @cfaester/enzyme-adapter-react-18
javascript
import Enzyme from 'enzyme';
import Adapter from '@cfaester/enzyme-adapter-react-18';

Enzyme.configure({ adapter: new Adapter() });

Create React App 集成 #

CRA 项目配置 #

Create React App 已经内置了 Jest,只需添加 Enzyme:

bash
# 安装依赖
npm install --save-dev enzyme @wojtekmaj/enzyme-adapter-react-17
javascript
// src/setupTests.js(CRA 会自动加载此文件)
import Enzyme from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';

Enzyme.configure({ adapter: new Adapter() });

TypeScript 支持 #

bash
# 安装类型定义
npm install --save-dev @types/enzyme
typescript
// src/setupTests.ts
import Enzyme from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';

Enzyme.configure({ adapter: new Adapter() });

// 添加全局类型声明
declare global {
  namespace NodeJS {
    interface Global {
      enzyme: typeof Enzyme;
    }
  }
}

Webpack 项目集成 #

安装依赖 #

bash
npm install --save-dev enzyme enzyme-adapter-react-16 jest babel-jest

Babel 配置 #

javascript
// babel.config.js
module.exports = {
  presets: [
    ['@babel/preset-env', { targets: { node: 'current' } }],
    '@babel/preset-react'
  ]
};

Jest 配置 #

javascript
// jest.config.js
module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/setupTests.js'],
  transform: {
    '^.+\\.jsx?$': 'babel-jest'
  }
};

Vite 项目集成 #

安装依赖 #

bash
npm install --save-dev enzyme @wojtekmaj/enzyme-adapter-react-17 jest jest-environment-jsdom

Jest 配置 #

javascript
// jest.config.js
module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/setupTests.js'],
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1'
  }
};

编写第一个测试 #

创建组件 #

javascript
// src/components/Button.js
import React from 'react';

function Button({ text, onClick }) {
  return (
    <button className="btn" onClick={onClick}>
      {text}
    </button>
  );
}

export default Button;

编写测试 #

javascript
// src/components/Button.test.js
import React from 'react';
import { shallow } from 'enzyme';
import Button from './Button';

describe('Button', () => {
  it('renders with correct text', () => {
    const wrapper = shallow(<Button text="Click me" />);
    expect(wrapper.text()).toBe('Click me');
  });

  it('has correct className', () => {
    const wrapper = shallow(<Button text="Click" />);
    expect(wrapper.hasClass('btn')).toBe(true);
  });

  it('handles click events', () => {
    const mockClick = jest.fn();
    const wrapper = shallow(<Button text="Click" onClick={mockClick} />);
    wrapper.simulate('click');
    expect(mockClick).toHaveBeenCalledTimes(1);
  });
});

运行测试 #

bash
# 运行所有测试
npm test

# 监听模式
npm test -- --watch

# 生成覆盖率报告
npm test -- --coverage

常见问题解决 #

问题 1:适配器未配置 #

text
Error: Enzyme Internal Error: `configure` was called but `adapter` was not configured

解决方案:

javascript
// 确保 setupTests.js 被正确加载
// 检查 jest.config.js 中的 setupFilesAfterEnv 配置

问题 2:React 版本不匹配 #

text
Error: React version not supported

解决方案:

bash
# 检查 React 版本
npm list react

# 安装对应的适配器
# React 16 -> enzyme-adapter-react-16
# React 17 -> @wojtekmaj/enzyme-adapter-react-17
# React 18 -> @cfaester/enzyme-adapter-react-18

问题 3:jsdom 环境问题 #

text
Error: The element you are trying to mount is not a valid DOM element

解决方案:

javascript
// jest.config.js
module.exports = {
  testEnvironment: 'jsdom'
};

问题 4:CSS 模块导入问题 #

text
SyntaxError: Unexpected token .

解决方案:

bash
npm install --save-dev identity-obj-proxy
javascript
// jest.config.js
module.exports = {
  moduleNameMapper: {
    '\\.module\\.css$': 'identity-obj-proxy'
  }
};

问题 5:静态资源导入问题 #

text
SyntaxError: Unexpected string

解决方案:

javascript
// __mocks__/fileMock.js
module.exports = 'test-file-stub';
javascript
// jest.config.js
module.exports = {
  moduleNameMapper: {
    '\\.(jpg|jpeg|png|gif|svg)$': '<rootDir>/__mocks__/fileMock.js'
  }
};

扩展配置 #

添加全局断言方法 #

javascript
// setupTests.js
import Enzyme from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';

Enzyme.configure({ adapter: new Adapter() });

// 自定义全局方法
expect.extend({
  toBeComponent(received, component) {
    const pass = received.is(component);
    return {
      pass,
      message: () => `expected ${received} ${pass ? 'not ' : ''}to be ${component}`
    };
  }
});

配置快照序列化 #

bash
npm install --save-dev enzyme-to-json
javascript
// setupTests.js
import { createSerializer } from 'enzyme-to-json';

expect.addSnapshotSerializer(createSerializer({ mode: 'deep' }));
javascript
// Button.test.js
import React from 'react';
import { shallow } from 'enzyme';
import Button from './Button';

it('matches snapshot', () => {
  const wrapper = shallow(<Button text="Click" />);
  expect(wrapper).toMatchSnapshot();
});

配置测试覆盖率 #

javascript
// jest.config.js
module.exports = {
  collectCoverage: true,
  coverageDirectory: 'coverage',
  coverageReporters: ['text', 'lcov', 'html'],
  coverageThreshold: {
    global: {
      branches: 80,
      functions: 80,
      lines: 80,
      statements: 80
    }
  }
};

下一步 #

现在你已经完成了 Enzyme 的安装和配置,接下来学习 浅层渲染 开始编写组件测试!

最后更新:2026-03-28