如何使用Jest测试包含两个纯组件的ImageBanner组件
Great question! When testing a component that conditionally renders child components based on props, we want to cover all possible scenarios: rendering only mobile, only desktop, both, or neither. Here's a step-by-step guide to writing comprehensive Jest tests for your ImageBanner component.
Prerequisites
Make sure you have these packages installed (if not already):
npm install --save-dev jest @testing-library/react @testing-library/jest-dom
Test Setup
First, let's assume your ImageBanner component is defined like this (based on your example):
// ImageBanner.jsx import MobileBanner from './MobileBanner'; import DesktopBanner from './DesktopBanner'; export default function ImageBanner({ mobile, desktop }) { return ( <div className="image-banner-container"> {mobile?.image && <MobileBanner mobile={mobile} />} {desktop?.image && <DesktopBanner desktop={desktop} />} </div> ); }
We'll mock the MobileBanner and DesktopBanner components in our tests to focus on how ImageBanner behaves, rather than testing the child components themselves (you can write separate tests for those pure components if needed).
Test Cases
Create a test file ImageBanner.test.jsx with the following tests:
import React from 'react'; import { render, screen } from '@testing-library/react'; import ImageBanner from './ImageBanner'; // Mock the child components with test IDs for easy querying jest.mock('./MobileBanner', () => ({ mobile }) => ( <div data-testid="mobile-banner" src={mobile.image} alt={mobile.alt} /> )); jest.mock('./DesktopBanner', () => ({ desktop }) => ( <div data-testid="desktop-banner" src={desktop.image} alt={desktop.alt} /> )); describe('ImageBanner Component', () => { // Reusable test data const mockMobileData = { image: 'mobile-banner.jpg', alt: 'Mobile promotional banner' }; const mockDesktopData = { image: 'desktop-banner.jpg', alt: 'Desktop promotional banner' }; it('renders only MobileBanner when mobile prop has image data', () => { render(<ImageBanner mobile={mockMobileData} desktop={{}} />); // Verify MobileBanner exists expect(screen.getByTestId('mobile-banner')).toBeInTheDocument(); // Verify DesktopBanner does NOT exist expect(screen.queryByTestId('desktop-banner')).not.toBeInTheDocument(); }); it('renders only DesktopBanner when desktop prop has image data', () => { render(<ImageBanner mobile={{}} desktop={mockDesktopData} />); expect(screen.getByTestId('desktop-banner')).toBeInTheDocument(); expect(screen.queryByTestId('mobile-banner')).not.toBeInTheDocument(); }); it('renders both banners when both props have image data', () => { render(<ImageBanner mobile={mockMobileData} desktop={mockDesktopData} />); expect(screen.getByTestId('mobile-banner')).toBeInTheDocument(); expect(screen.getByTestId('desktop-banner')).toBeInTheDocument(); }); it('renders nothing when neither prop has image data', () => { const { container } = render(<ImageBanner mobile={{}} desktop={{}} />); // Check the wrapper div has no child elements expect(container.firstChild.children).toHaveLength(0); }); it('passes correct props to MobileBanner when rendered', () => { render(<ImageBanner mobile={mockMobileData} />); const mobileBanner = screen.getByTestId('mobile-banner'); expect(mobileBanner).toHaveAttribute('src', mockMobileData.image); expect(mobileBanner).toHaveAttribute('alt', mockMobileData.alt); }); it('passes correct props to DesktopBanner when rendered', () => { render(<ImageBanner desktop={mockDesktopData} />); const desktopBanner = screen.getByTestId('desktop-banner'); expect(desktopBanner).toHaveAttribute('src', mockDesktopData.image); expect(desktopBanner).toHaveAttribute('alt', mockDesktopData.alt); }); });
Key Explanations
- Mocking Child Components: We use
jest.mockto replace the actual banner components with simple mocks that includedata-testidattributes. This lets us isolate theImageBannerlogic without worrying about the child components' internal HTML. - Query Methods:
getByTestIdis used when we expect an element to exist (it throws an error if not found), whilequeryByTestIdis used when we expect an element to NOT exist (it returnsnullinstead of throwing). - Prop Validation: We verify that the correct props are passed down to the child components, ensuring data flows as expected.
Alternative: Testing Without Mocking
If you prefer to test against the actual rendered HTML of your pure banner components, skip mocking and check for elements specific to those components. For example, if MobileBanner renders an <img> tag:
it('renders MobileBanner with correct image', () => { render(<ImageBanner mobile={mockMobileData} />); expect(screen.getByAltText('Mobile promotional banner')).toHaveAttribute('src', 'mobile-banner.jpg'); });
This approach validates the full component tree but is less focused on isolating ImageBanner's conditional logic.
内容的提问来源于stack exchange,提问作者RRP

