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 }) => (
{title}
),
}))
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
}) => (
onChange(e.target.value)}
data-testid="search-input-field"
/>
),
}))
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(
{component}
)
}
it('渲染页面标题和布局', () => {
renderWithProviders()
expect(screen.getByTestId('navbar')).toBeInTheDocument()
expect(screen.getByText('搜索')).toBeInTheDocument()
})
it('显示搜索输入框', () => {
renderWithProviders()
expect(screen.getByTestId('search-input')).toBeInTheDocument()
expect(screen.getByPlaceholderText('搜索商品...')).toBeInTheDocument()
})
it('显示搜索历史', async () => {
renderWithProviders()
await waitFor(() => {
expect(screen.getByText('搜索历史')).toBeInTheDocument()
expect(screen.getByText('手机')).toBeInTheDocument()
expect(screen.getByText('耳机')).toBeInTheDocument()
expect(screen.getByText('笔记本电脑')).toBeInTheDocument()
expect(screen.getByText('清空')).toBeInTheDocument()
})
})
it('显示热门搜索', async () => {
renderWithProviders()
await waitFor(() => {
expect(screen.getByText('热门搜索')).toBeInTheDocument()
expect(screen.getByText('手机')).toBeInTheDocument()
expect(screen.getByText('笔记本电脑')).toBeInTheDocument()
expect(screen.getByText('耳机')).toBeInTheDocument()
expect(screen.getByText('智能手表')).toBeInTheDocument()
})
})
it('显示空状态', async () => {
// 模拟没有搜索历史和热门搜索的情况
mockGetStorageSync.mockReturnValue([])
renderWithProviders()
await waitFor(() => {
expect(screen.getByText('暂无搜索记录')).toBeInTheDocument()
expect(screen.getByText('输入关键词搜索商品')).toBeInTheDocument()
})
})
it('处理搜索提交', async () => {
renderWithProviders()
// 输入搜索关键词
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()
await waitFor(() => {
const historyItem = screen.getByText('手机')
fireEvent.click(historyItem)
// 验证保存搜索历史
expect(mockSetStorageSync).toHaveBeenCalledWith('search_history', ['手机', '耳机', '笔记本电脑'])
// 验证跳转到搜索结果页面
expect(mockNavigateTo).toHaveBeenCalledWith({
url: '/pages/search-result/index?keyword=手机'
})
})
})
it('点击热门搜索项', async () => {
renderWithProviders()
await waitFor(() => {
const popularItem = screen.getByText('智能手表')
fireEvent.click(popularItem)
// 验证保存搜索历史
expect(mockSetStorageSync).toHaveBeenCalledWith('search_history', ['智能手表', '手机', '耳机', '笔记本电脑'])
// 验证跳转到搜索结果页面
expect(mockNavigateTo).toHaveBeenCalledWith({
url: '/pages/search-result/index?keyword=智能手表'
})
})
})
it('清空搜索历史', async () => {
renderWithProviders()
await waitFor(() => {
const clearButton = screen.getByText('清空')
fireEvent.click(clearButton)
// 验证清空搜索历史
expect(mockRemoveStorageSync).toHaveBeenCalledWith('search_history')
})
})
it('处理搜索输入框清除', () => {
renderWithProviders()
// 输入搜索关键词
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()
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)
})
})
})