如何用Jest测试React商品列表组件的价格筛选功能?
React商品列表组件价格筛选功能的Jest测试方案
一、能否用Jest测试该功能?
完全可以。Jest配合React Testing Library是React组件单元测试的主流方案,能够覆盖状态更新、函数逻辑、UI渲染变化等核心场景,你的价格筛选功能完全可以用这套组合测试。
二、具体实现步骤
1. 安装必要依赖
确保项目已安装以下依赖:
npm install --save-dev jest @testing-library/react @testing-library/jest-dom @testing-library/user-event
2. 创建测试文件
在组件目录下创建ProductsList.test.js文件。
3. 编写测试用例
以下是针对价格筛选功能的核心测试用例:
(1)测试基础初始化与上下文数据注入
首先需要模拟ContextProvider和useParams的返回值,因为组件依赖这两个外部数据:
import React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import ProductsList from './ProductsList'; import { ContextProvider } from '../../Others/AuthContext/authContext'; import { MemoryRouter, Routes, Route } from 'react-router-dom'; // 模拟测试用商品数据 const mockProducts = [ { _id: '1', name: '手链1', price: '100', category: 'Bracelet', img: ['img1.jpg'] }, { _id: '2', name: '手链2', price: '500', category: 'Bracelet', img: ['img2.jpg'] }, { _id: '3', name: '手链3', price: '1000', category: 'Bracelet', img: ['img3.jpg'] }, ]; // 包裹组件的辅助函数 const renderWithProviders = (productId = 'Bracelet') => { return render( <ContextProvider value={{ data: { Bracelet: mockProducts } }}> <MemoryRouter initialEntries={[`/products/${productId}`]}> <Routes> <Route path="/products/:productId" element={<ProductsList />} /> </Routes> </MemoryRouter> </ContextProvider> ); };
(2)测试滑块更新价格状态
验证拖动滑块时priceFrom和priceTo状态是否正确更新:
test('价格滑块拖动时更新priceFrom和priceTo状态', async () => { const user = userEvent.setup(); renderWithProviders(); // 找到滑块的两个thumb元素 const thumbs = screen.getAllByRole('slider'); expect(thumbs).toHaveLength(2); // 拖动第一个thumb到200的位置 await user.drag(thumbs[0], { target: { value: 200 } }); // 拖动第二个thumb到800的位置 await user.drag(thumbs[1], { target: { value: 800 } }); // 验证滑块显示的数值是否正确 expect(thumbs[0]).toHaveTextContent('200'); expect(thumbs[1]).toHaveTextContent('800'); });
(3)测试筛选功能正常工作
验证点击Apply按钮后,商品列表正确筛选:
test('点击Apply按钮后正确筛选价格区间内的商品', async () => { const user = userEvent.setup(); renderWithProviders(); // 设置价格区间 const thumbs = screen.getAllByRole('slider'); await user.drag(thumbs[0], { target: { value: 200 } }); await user.drag(thumbs[1], { target: { value: 800 } }); // 点击Apply按钮 const applyBtn = screen.getByRole('button', { name: /apply/i }); await user.click(applyBtn); // 验证只显示价格在200-800之间的商品(手链2,价格500) const productNames = screen.getAllByText(/手链/i); expect(productNames).toHaveLength(1); expect(productNames[0]).toHaveTextContent('手链2'); });
(4)测试无匹配商品的场景
验证当筛选无结果时,显示正确的提示:
test('筛选无匹配商品时显示"Nothing found"提示', async () => { const user = userEvent.setup(); renderWithProviders(); // 设置一个没有商品匹配的区间 const thumbs = screen.getAllByRole('slider'); await user.drag(thumbs[0], { target: { value: 1500 } }); await user.drag(thumbs[1], { target: { value: 2000 } }); // 点击Apply按钮 const applyBtn = screen.getByRole('button', { name: /apply/i }); await user.click(applyBtn); // 验证提示文本 expect(screen.getByText(/Nothing found based on your range/i)).toBeInTheDocument(); });
(5)测试重置筛选功能
验证点击Reset按钮后,价格区间和商品列表恢复初始状态:
test('点击Reset按钮后重置价格区间和商品列表', async () => { const user = userEvent.setup(); renderWithProviders(); // 修改价格区间并应用筛选 const thumbs = screen.getAllByRole('slider'); await user.drag(thumbs[0], { target: { value: 200 } }); await user.drag(thumbs[1], { target: { value: 800 } }); const applyBtn = screen.getByRole('button', { name: /apply/i }); await user.click(applyBtn); // 点击Reset按钮 const resetBtn = screen.getByRole('button', { name: /reset/i }); await user.click(resetBtn); // 验证滑块回到初始值(0和1000) expect(thumbs[0]).toHaveTextContent('0'); expect(thumbs[1]).toHaveTextContent('1000'); // 验证商品列表恢复为3个 expect(screen.getAllByText(/手链/i)).toHaveLength(3); });
三、替代测试方案
如果你的测试需求更侧重端到端的用户交互流程(比如从打开页面到完成筛选的完整操作),可以选择:
- Cypress:适合编写端到端测试,模拟真实用户操作,覆盖完整流程。
- Playwright:跨浏览器的端到端测试工具,功能强大,支持多种浏览器。
如果希望单独测试filterItem函数的逻辑,可以把该函数从组件中抽离出来,编写独立的纯函数测试,不需要依赖React组件环境:
// 抽离filterItem逻辑为纯函数 export const filterProducts = (products, priceFrom, priceTo) => { if (!priceFrom || !priceTo) return []; return products.filter(item => Number(item.price) >= priceFrom && Number(item.price) <= priceTo); }; // 纯函数测试用例 test('filterProducts正确筛选价格区间', () => { const testProducts = [ { price: '100' }, { price: '500' }, { price: '1000' } ]; expect(filterProducts(testProducts, 200, 800)).toEqual([{ price: '500' }]); });
内容的提问来源于stack exchange,提问作者Aminur Rahman
相关产品推荐
相关产品推荐

