# antd-component-testing > Tests Ant Design components in Jest environment. Invoke when testing React apps using Ant Design components or handling Form, message, Modal components. - Author: corvozhang - Repository: CorvoZhang/Wardrobe_mini - Version: 20260121112047 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-06 - Source: https://github.com/CorvoZhang/Wardrobe_mini - Web: https://mule.run/skillshub/@@CorvoZhang/Wardrobe_mini~antd-component-testing:20260121112047 --- --- name: antd-component-testing description: Tests Ant Design components in Jest environment. Invoke when testing React apps using Ant Design components or handling Form, message, Modal components. --- # Ant Design 组件测试指南 ## 概述 本文档描述如何在 Jest 环境中测试 Ant Design 组件,包括必要的 mock 和常见问题处理。 ## 适用场景 - 测试使用 Ant Design 组件的 React 应用 - 处理 Form、message、Modal 等复杂组件 - 解决 JSDOM 环境限制问题 --- ## 1. 必要的浏览器 API Mock ### 1.1 window.matchMedia(必需) ```javascript // setupTests.js Object.defineProperty(window, 'matchMedia', { writable: true, value: jest.fn().mockImplementation(query => ({ matches: false, media: query, onchange: null, addListener: jest.fn(), // 旧版 API removeListener: jest.fn(), // 旧版 API addEventListener: jest.fn(), removeEventListener: jest.fn(), dispatchEvent: jest.fn(), })), }); ``` **影响的组件**: Grid、Layout、Menu(响应式)、所有使用 useBreakpoint 的组件 ### 1.2 ResizeObserver ```javascript class MockResizeObserver { constructor(callback) { this.callback = callback; } observe() {} unobserve() {} disconnect() {} } global.ResizeObserver = MockResizeObserver; ``` **影响的组件**: Table、Tabs、虚拟列表组件 ### 1.3 IntersectionObserver ```javascript class MockIntersectionObserver { constructor(callback) { this.callback = callback; } observe() {} unobserve() {} disconnect() {} } global.IntersectionObserver = MockIntersectionObserver; ``` **影响的组件**: Image(懒加载)、无限滚动组件 ### 1.4 MutationObserver ```javascript class MockMutationObserver { constructor(callback) { this.callback = callback; } observe() {} disconnect() {} takeRecords() { return []; } } global.MutationObserver = MockMutationObserver; ``` ### 1.5 其他常用 Mock ```javascript // scrollTo window.scrollTo = jest.fn(); Element.prototype.scrollTo = jest.fn(); Element.prototype.scrollIntoView = jest.fn(); // requestAnimationFrame global.requestAnimationFrame = (cb) => setTimeout(cb, 0); global.cancelAnimationFrame = (id) => clearTimeout(id); // getComputedStyle 增强 const originalGetComputedStyle = window.getComputedStyle; window.getComputedStyle = (elt, pseudoElt) => { const style = originalGetComputedStyle(elt, pseudoElt); return { ...style, getPropertyValue: (prop) => style.getPropertyValue(prop) || '', }; }; ``` --- ## 2. 组件专项 Mock ### 2.1 message API ```javascript jest.mock('antd', () => { const antd = jest.requireActual('antd'); return { ...antd, message: { success: jest.fn(), error: jest.fn(), warning: jest.fn(), info: jest.fn(), loading: jest.fn(), destroy: jest.fn(), }, }; }); ``` **使用示例**: ```javascript import { message } from 'antd'; it('should show success message', async () => { // 触发操作... await waitFor(() => { expect(message.success).toHaveBeenCalledWith('操作成功'); }); }); ``` ### 2.2 Modal.confirm ```javascript jest.mock('antd', () => { const antd = jest.requireActual('antd'); return { ...antd, Modal: { ...antd.Modal, confirm: jest.fn(({ onOk, onCancel }) => ({ destroy: jest.fn(), update: jest.fn(), })), }, }; }); ``` ### 2.3 notification API ```javascript jest.mock('antd', () => { const antd = jest.requireActual('antd'); return { ...antd, notification: { success: jest.fn(), error: jest.fn(), info: jest.fn(), warning: jest.fn(), open: jest.fn(), destroy: jest.fn(), }, }; }); ``` --- ## 3. Form 组件测试 ### 3.1 基本表单测试 ```javascript it('should validate form fields', async () => { const user = userEvent.setup(); await act(async () => { render(); }); // 点击提交触发验证 await act(async () => { await user.click(screen.getByRole('button', { name: /提交/i })); }); // 等待异步验证完成 await waitFor(() => { expect(screen.getByText(/请输入/i)).toBeInTheDocument(); }, { timeout: 3000 }); }); ``` ### 3.2 Form 验证消息查找技巧 ```javascript // 方法1: 按文本查找 expect(screen.getByText(/请输入邮箱/i)).toBeInTheDocument(); // 方法2: 查找带错误状态的元素 const formItem = screen.getByRole('textbox', { name: /邮箱/i }) .closest('.ant-form-item'); expect(formItem).toHaveClass('ant-form-item-has-error'); // 方法3: 查找所有错误消息 const errors = screen.getAllByText(/请输入/i); expect(errors.length).toBeGreaterThan(0); ``` --- ## 4. 常见问题解决 ### 问题1: act() 警告 ``` Warning: An update to Component inside a test was not wrapped in act(...) ``` **解决**: 所有触发状态更新的操作都包装在 `act()` 中 ```javascript await act(async () => { await user.click(button); }); ``` ### 问题2: 找不到 Portal 渲染的内容 **原因**: Modal、Dropdown、Tooltip 等使用 Portal 渲染到 body **解决**: 使用 `screen.getByRole` 或 `document.body` 查询 ```javascript // Modal 内容 const modal = screen.getByRole('dialog'); expect(modal).toBeInTheDocument(); ``` ### 问题3: 下拉菜单选项找不到 **原因**: 下拉内容在点击前不渲染 **解决**: 先触发点击,再查找选项 ```javascript await user.click(screen.getByRole('combobox')); await waitFor(() => { expect(screen.getByText('选项1')).toBeInTheDocument(); }); ``` ### 问题4: 动画导致测试不稳定 **解决**: 禁用动画或增加等待时间 ```javascript // 全局禁用动画 import { ConfigProvider } from 'antd'; render( ); ``` --- ## 5. 控制台警告过滤 ```javascript // setupTests.js const originalConsoleError = console.error; const originalConsoleWarn = console.warn; beforeAll(() => { console.error = (...args) => { if ( args[0]?.includes?.('Warning: ReactDOM.render') || args[0]?.includes?.('act(...)') || args[0]?.includes?.('Not implemented: HTMLFormElement') ) return; originalConsoleError.apply(console, args); }; console.warn = (...args) => { if ( args[0]?.includes?.('componentWillReceiveProps') || args[0]?.includes?.('componentWillUpdate') || args[0]?.includes?.('React Router Future Flag') ) return; originalConsoleWarn.apply(console, args); }; }); afterAll(() => { console.error = originalConsoleError; console.warn = originalConsoleWarn; }); ```