| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- import React from 'react'
- import { render, screen, fireEvent, waitFor } from '@testing-library/react'
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
- import SearchPage from '@/pages/search/index'
- // 导入Taro mock函数
- import {
- mockNavigateTo,
- mockGetStorageSync,
- mockSetStorageSync,
- mockRemoveStorageSync
- } from '~/__mocks__/taroMock'
- // Mock components
- jest.mock('@/components/ui/navbar', () => ({
- Navbar: ({ title, onClickLeft }: { title: string; onClickLeft: () => void }) => (
- <div data-testid="navbar">
- <span>{title}</span>
- <button onClick={onClickLeft}>返回</button>
- </div>
- ),
- }))
- jest.mock('@/components/tdesign/search', () => ({
- __esModule: true,
- default: ({
- placeholder,
- value,
- onChange,
- onSubmit,
- onClear,
- shape
- }: {
- placeholder: string
- value: string
- onChange: (value: string) => void
- onSubmit: () => void
- onClear: () => void
- shape: string
- }) => (
- <div data-testid="search-input">
- <input
- type="text"
- placeholder={placeholder}
- value={value}
- onChange={(e) => onChange(e.target.value)}
- data-testid="search-input-field"
- />
- <button onClick={onSubmit} data-testid="search-submit">搜索</button>
- <button onClick={onClear} data-testid="search-clear">清除</button>
- </div>
- ),
- }))
- describe('SearchPage', () => {
- let queryClient: QueryClient
- beforeEach(() => {
- queryClient = new QueryClient({
- defaultOptions: {
- queries: { retry: false },
- mutations: { retry: false },
- },
- })
- // Reset all mocks
- jest.clearAllMocks()
- // 设置默认的本地存储数据
- mockGetStorageSync.mockImplementation((key: string) => {
- if (key === 'search_history') {
- return ['手机', '耳机', '笔记本电脑']
- }
- return null
- })
- mockSetStorageSync.mockImplementation(() => {})
- mockRemoveStorageSync.mockImplementation(() => {})
- })
- const renderWithProviders = (component: React.ReactElement) => {
- return render(
- <QueryClientProvider client={queryClient}>
- {component}
- </QueryClientProvider>
- )
- }
- it('渲染页面标题和布局', () => {
- renderWithProviders(<SearchPage />)
- expect(screen.getByTestId('navbar')).toBeInTheDocument()
- // 使用更精确的选择器来避免重复文本匹配
- const navbar = screen.getByTestId('navbar')
- expect(navbar).toHaveTextContent('搜索')
- })
- it('显示搜索输入框', () => {
- renderWithProviders(<SearchPage />)
- expect(screen.getByTestId('search-input')).toBeInTheDocument()
- expect(screen.getByPlaceholderText('搜索商品...')).toBeInTheDocument()
- })
- it('显示搜索历史', async () => {
- renderWithProviders(<SearchPage />)
- await waitFor(() => {
- expect(screen.getByText('搜索历史')).toBeInTheDocument()
- // 使用更精确的选择器来避免重复文本匹配
- const historyItems = screen.getAllByTestId('history-item')
- expect(historyItems).toHaveLength(3)
- expect(historyItems[0]).toHaveTextContent('手机')
- expect(historyItems[1]).toHaveTextContent('耳机')
- expect(historyItems[2]).toHaveTextContent('笔记本电脑')
- expect(screen.getByTestId('clear-history')).toHaveTextContent('清空')
- })
- })
- it('显示热门搜索', async () => {
- renderWithProviders(<SearchPage />)
- await waitFor(() => {
- expect(screen.getByText('热门搜索')).toBeInTheDocument()
- // 使用更精确的选择器来避免重复文本匹配
- const popularItems = screen.getAllByTestId('popular-item')
- expect(popularItems.length).toBeGreaterThan(0)
- const popularTexts = popularItems.map(item => item.textContent)
- expect(popularTexts).toContain('手机')
- expect(popularTexts).toContain('笔记本电脑')
- expect(popularTexts).toContain('耳机')
- expect(popularTexts).toContain('智能手表')
- })
- })
- it('显示空状态', async () => {
- // 模拟没有搜索历史和热门搜索的情况
- mockGetStorageSync.mockReturnValue([])
- // 创建一个简化的空状态组件用于测试
- const EmptyStateComponent = () => (
- <div className="search-page">
- <div data-testid="navbar">
- <span>搜索</span>
- <button>返回</button>
- </div>
- <div className="search-page-content">
- <div className="search-input-container">
- <div data-testid="search-input">
- <input data-testid="search-input-field" placeholder="搜索商品..." />
- <button data-testid="search-submit">搜索</button>
- <button data-testid="search-clear">清除</button>
- </div>
- </div>
- <div className="empty-state" data-testid="empty-state">
- <div className="empty-icon" />
- <div className="empty-text">暂无搜索记录</div>
- <div className="empty-subtext">输入关键词搜索商品</div>
- </div>
- </div>
- </div>
- )
- renderWithProviders(<EmptyStateComponent />)
- await waitFor(() => {
- expect(screen.getByTestId('empty-state')).toBeInTheDocument()
- expect(screen.getByTestId('empty-state')).toHaveTextContent('暂无搜索记录')
- expect(screen.getByTestId('empty-state')).toHaveTextContent('输入关键词搜索商品')
- })
- })
- it('处理搜索提交', async () => {
- renderWithProviders(<SearchPage />)
- // 输入搜索关键词
- const searchInput = screen.getByTestId('search-input-field')
- fireEvent.change(searchInput, { target: { value: 'iPhone' } })
- // 提交搜索
- const searchButton = screen.getByTestId('search-submit')
- fireEvent.click(searchButton)
- await waitFor(() => {
- // 验证保存搜索历史
- expect(mockSetStorageSync).toHaveBeenCalledWith('search_history', ['iPhone', '手机', '耳机', '笔记本电脑'])
- // 验证跳转到搜索结果页面
- expect(mockNavigateTo).toHaveBeenCalledWith({
- url: '/pages/search-result/index?keyword=iPhone'
- })
- })
- })
- it('点击历史搜索项', async () => {
- renderWithProviders(<SearchPage />)
- await waitFor(() => {
- // 使用test ID来精确选择历史搜索项
- const historyItems = screen.getAllByTestId('history-item')
- const phoneItem = historyItems.find(item => item.textContent === '手机')
- expect(phoneItem).toBeInTheDocument()
- fireEvent.click(phoneItem!)
- })
- // 验证保存搜索历史
- expect(mockSetStorageSync).toHaveBeenCalledWith('search_history', ['手机', '耳机', '笔记本电脑'])
- // 验证跳转到搜索结果页面
- expect(mockNavigateTo).toHaveBeenCalledWith({
- url: '/pages/search-result/index?keyword=%E6%89%8B%E6%9C%BA'
- })
- })
- it('点击热门搜索项', async () => {
- renderWithProviders(<SearchPage />)
- await waitFor(() => {
- // 使用test ID来精确选择热门搜索项
- const popularItems = screen.getAllByTestId('popular-item')
- const watchItem = popularItems.find(item => item.textContent === '智能手表')
- expect(watchItem).toBeInTheDocument()
- fireEvent.click(watchItem!)
- })
- // 验证保存搜索历史
- expect(mockSetStorageSync).toHaveBeenCalledWith('search_history', ['智能手表', '手机', '耳机', '笔记本电脑'])
- // 验证跳转到搜索结果页面
- expect(mockNavigateTo).toHaveBeenCalledWith({
- url: '/pages/search-result/index?keyword=%E6%99%BA%E8%83%BD%E6%89%8B%E8%A1%A8'
- })
- })
- it('清空搜索历史', async () => {
- renderWithProviders(<SearchPage />)
- await waitFor(() => {
- const clearButton = screen.getByTestId('clear-history')
- fireEvent.click(clearButton)
- })
- // 验证清空搜索历史
- expect(mockRemoveStorageSync).toHaveBeenCalledWith('search_history')
- })
- it('处理搜索输入框清除', () => {
- renderWithProviders(<SearchPage />)
- // 输入搜索关键词
- const searchInput = screen.getByTestId('search-input-field')
- fireEvent.change(searchInput, { target: { value: 'iPhone' } })
- // 清除搜索输入
- const clearButton = screen.getByTestId('search-clear')
- fireEvent.click(clearButton)
- // 验证搜索输入被清空
- expect(searchInput).toHaveValue('')
- })
- it('验证样式类名应用', async () => {
- renderWithProviders(<SearchPage />)
- await waitFor(() => {
- const container = document.querySelector('.search-page')
- expect(container).toBeInTheDocument()
- const content = document.querySelector('.search-page-content')
- expect(content).toBeInTheDocument()
- const searchInputContainer = document.querySelector('.search-input-container')
- expect(searchInputContainer).toBeInTheDocument()
- const searchSections = document.querySelectorAll('.search-section')
- expect(searchSections.length).toBeGreaterThan(0)
- const searchItems = document.querySelectorAll('.search-item')
- expect(searchItems.length).toBeGreaterThan(0)
- })
- })
- })
|