使用Jest测试ReactJS组件异步渲染:验证子组件按数据渲染
Let's break down how to write this test step by step. First, I'll assume your component fetches the data array (either synchronously or asynchronously) and renders a SubComponent for each item—here's how to validate that behavior with Jest and React Testing Library (which works great with React 16.2).
Step 1: Mock the External Library
First, we need to mock externalLibrary so its doStuff() method returns our controlled 3-item array. This ensures our test doesn't depend on real external behavior.
// At the top of your test file import React from 'react'; import { render, screen } from '@testing-library/react'; import MyComponent from './MyComponent'; import externalLibrary from 'external-library'; // Mock the entire external library jest.mock('external-library', () => ({ doStuff: jest.fn(() => [ { id: 1, label: 'First Item' }, { id: 2, label: 'Second Item' }, { id: 3, label: 'Third Item' } ]) }));
Step 2: Write the Test Case
We'll cover two common scenarios: synchronous data loading and asynchronous data loading (since you mentioned React's async test examples, this covers both cases).
Scenario 1: Synchronous Data Loading
If your component sets state immediately after calling doStuff() (e.g., in componentDidMount), the test can directly query the rendered components:
describe('MyComponent', () => { it('renders one SubComponent for each item in the data array', () => { // Render the component render(<MyComponent />); // Get all instances of SubComponent using a test ID (add this to your SubComponent!) // In SubComponent.jsx, add: <div data-testid="sub-component">...</div> const subComponents = screen.getAllByTestId('sub-component'); // Verify we have exactly 3 SubComponents expect(subComponents).toHaveLength(3); // Optional: Verify each item's content is rendered (if relevant) expect(screen.getByText('First Item')).toBeInTheDocument(); expect(screen.getByText('Second Item')).toBeInTheDocument(); expect(screen.getByText('Third Item')).toBeInTheDocument(); }); });
Scenario 2: Asynchronous Data Loading
If doStuff() returns a Promise (common for API calls), we need to wait for the component to update after resolving the Promise. Use async/await with Testing Library's findBy* or findAllBy* methods, which automatically wait for elements to appear:
it('renders SubComponents after async data loads', async () => { // Override the mock to return a Promise instead externalLibrary.doStuff.mockResolvedValue([ { id: 1, label: 'Async Item 1' }, { id: 2, label: 'Async Item 2' }, { id: 3, label: 'Async Item 3' } ]); render(<MyComponent />); // Wait for all SubComponents to render const subComponents = await screen.findAllByTestId('sub-component'); expect(subComponents).toHaveLength(3); // Verify async content expect(await screen.findByText('Async Item 1')).toBeInTheDocument(); });
Key Notes
- Add a test ID to SubComponent: Using
data-testidis a stable way to query components without relying on text or CSS classes that might change. - React Testing Library vs Enzyme: Testing Library is recommended here because it focuses on user-centric testing (what the user sees) rather than implementation details, which aligns with your goal of verifying the final render result.
- React 16.2 Compatibility: React Testing Library supports React 16.0+, so this works perfectly with your version.
Example SubComponent
Just to make sure the test ID makes sense, here's a simple SubComponent implementation:
// SubComponent.jsx import React from 'react'; const SubComponent = ({ item }) => { return ( <div data-testid="sub-component"> {item.label} </div> ); }; export default SubComponent;
内容的提问来源于stack exchange,提问作者Arbiter

