basic.test.tsx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import React from 'react'
  2. import { render, screen, fireEvent, waitFor } from '@testing-library/react'
  3. import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
  4. import SearchPage from '@/pages/search/index'
  5. // 导入Taro mock函数
  6. import {
  7. mockNavigateTo,
  8. mockGetStorageSync,
  9. mockSetStorageSync,
  10. mockRemoveStorageSync
  11. } from '~/__mocks__/taroMock'
  12. // Mock components
  13. jest.mock('@/components/ui/navbar', () => ({
  14. Navbar: ({ title, onClickLeft }: { title: string; onClickLeft: () => void }) => (
  15. <div data-testid="navbar">
  16. <span>{title}</span>
  17. <button onClick={onClickLeft}>返回</button>
  18. </div>
  19. ),
  20. }))
  21. jest.mock('@/components/tdesign/search', () => ({
  22. __esModule: true,
  23. default: ({
  24. placeholder,
  25. value,
  26. onChange,
  27. onSubmit,
  28. onClear,
  29. shape
  30. }: {
  31. placeholder: string
  32. value: string
  33. onChange: (value: string) => void
  34. onSubmit: () => void
  35. onClear: () => void
  36. shape: string
  37. }) => (
  38. <div data-testid="search-input">
  39. <input
  40. type="text"
  41. placeholder={placeholder}
  42. value={value}
  43. onChange={(e) => onChange(e.target.value)}
  44. data-testid="search-input-field"
  45. />
  46. <button onClick={onSubmit} data-testid="search-submit">搜索</button>
  47. <button onClick={onClear} data-testid="search-clear">清除</button>
  48. </div>
  49. ),
  50. }))
  51. describe('SearchPage', () => {
  52. let queryClient: QueryClient
  53. beforeEach(() => {
  54. queryClient = new QueryClient({
  55. defaultOptions: {
  56. queries: { retry: false },
  57. mutations: { retry: false },
  58. },
  59. })
  60. // Reset all mocks
  61. jest.clearAllMocks()
  62. // 设置默认的本地存储数据
  63. mockGetStorageSync.mockImplementation((key: string) => {
  64. if (key === 'search_history') {
  65. return ['手机', '耳机', '笔记本电脑']
  66. }
  67. return null
  68. })
  69. mockSetStorageSync.mockImplementation(() => {})
  70. mockRemoveStorageSync.mockImplementation(() => {})
  71. })
  72. const renderWithProviders = (component: React.ReactElement) => {
  73. return render(
  74. <QueryClientProvider client={queryClient}>
  75. {component}
  76. </QueryClientProvider>
  77. )
  78. }
  79. it('渲染页面标题和布局', () => {
  80. renderWithProviders(<SearchPage />)
  81. expect(screen.getByTestId('navbar')).toBeInTheDocument()
  82. expect(screen.getByText('搜索')).toBeInTheDocument()
  83. })
  84. it('显示搜索输入框', () => {
  85. renderWithProviders(<SearchPage />)
  86. expect(screen.getByTestId('search-input')).toBeInTheDocument()
  87. expect(screen.getByPlaceholderText('搜索商品...')).toBeInTheDocument()
  88. })
  89. it('显示搜索历史', async () => {
  90. renderWithProviders(<SearchPage />)
  91. await waitFor(() => {
  92. expect(screen.getByText('搜索历史')).toBeInTheDocument()
  93. expect(screen.getByText('手机')).toBeInTheDocument()
  94. expect(screen.getByText('耳机')).toBeInTheDocument()
  95. expect(screen.getByText('笔记本电脑')).toBeInTheDocument()
  96. expect(screen.getByText('清空')).toBeInTheDocument()
  97. })
  98. })
  99. it('显示热门搜索', async () => {
  100. renderWithProviders(<SearchPage />)
  101. await waitFor(() => {
  102. expect(screen.getByText('热门搜索')).toBeInTheDocument()
  103. expect(screen.getByText('手机')).toBeInTheDocument()
  104. expect(screen.getByText('笔记本电脑')).toBeInTheDocument()
  105. expect(screen.getByText('耳机')).toBeInTheDocument()
  106. expect(screen.getByText('智能手表')).toBeInTheDocument()
  107. })
  108. })
  109. it('显示空状态', async () => {
  110. // 模拟没有搜索历史和热门搜索的情况
  111. mockGetStorageSync.mockReturnValue([])
  112. renderWithProviders(<SearchPage />)
  113. await waitFor(() => {
  114. expect(screen.getByText('暂无搜索记录')).toBeInTheDocument()
  115. expect(screen.getByText('输入关键词搜索商品')).toBeInTheDocument()
  116. })
  117. })
  118. it('处理搜索提交', async () => {
  119. renderWithProviders(<SearchPage />)
  120. // 输入搜索关键词
  121. const searchInput = screen.getByTestId('search-input-field')
  122. fireEvent.change(searchInput, { target: { value: 'iPhone' } })
  123. // 提交搜索
  124. const searchButton = screen.getByTestId('search-submit')
  125. fireEvent.click(searchButton)
  126. await waitFor(() => {
  127. // 验证保存搜索历史
  128. expect(mockSetStorageSync).toHaveBeenCalledWith('search_history', ['iPhone', '手机', '耳机', '笔记本电脑'])
  129. // 验证跳转到搜索结果页面
  130. expect(mockNavigateTo).toHaveBeenCalledWith({
  131. url: '/pages/search-result/index?keyword=iPhone'
  132. })
  133. })
  134. })
  135. it('点击历史搜索项', async () => {
  136. renderWithProviders(<SearchPage />)
  137. await waitFor(() => {
  138. const historyItem = screen.getByText('手机')
  139. fireEvent.click(historyItem)
  140. // 验证保存搜索历史
  141. expect(mockSetStorageSync).toHaveBeenCalledWith('search_history', ['手机', '耳机', '笔记本电脑'])
  142. // 验证跳转到搜索结果页面
  143. expect(mockNavigateTo).toHaveBeenCalledWith({
  144. url: '/pages/search-result/index?keyword=手机'
  145. })
  146. })
  147. })
  148. it('点击热门搜索项', async () => {
  149. renderWithProviders(<SearchPage />)
  150. await waitFor(() => {
  151. const popularItem = screen.getByText('智能手表')
  152. fireEvent.click(popularItem)
  153. // 验证保存搜索历史
  154. expect(mockSetStorageSync).toHaveBeenCalledWith('search_history', ['智能手表', '手机', '耳机', '笔记本电脑'])
  155. // 验证跳转到搜索结果页面
  156. expect(mockNavigateTo).toHaveBeenCalledWith({
  157. url: '/pages/search-result/index?keyword=智能手表'
  158. })
  159. })
  160. })
  161. it('清空搜索历史', async () => {
  162. renderWithProviders(<SearchPage />)
  163. await waitFor(() => {
  164. const clearButton = screen.getByText('清空')
  165. fireEvent.click(clearButton)
  166. // 验证清空搜索历史
  167. expect(mockRemoveStorageSync).toHaveBeenCalledWith('search_history')
  168. })
  169. })
  170. it('处理搜索输入框清除', () => {
  171. renderWithProviders(<SearchPage />)
  172. // 输入搜索关键词
  173. const searchInput = screen.getByTestId('search-input-field')
  174. fireEvent.change(searchInput, { target: { value: 'iPhone' } })
  175. // 清除搜索输入
  176. const clearButton = screen.getByTestId('search-clear')
  177. fireEvent.click(clearButton)
  178. // 验证搜索输入被清空
  179. expect(searchInput).toHaveValue('')
  180. })
  181. it('验证样式类名应用', async () => {
  182. renderWithProviders(<SearchPage />)
  183. await waitFor(() => {
  184. const container = document.querySelector('.search-page')
  185. expect(container).toBeInTheDocument()
  186. const content = document.querySelector('.search-page-content')
  187. expect(content).toBeInTheDocument()
  188. const searchInputContainer = document.querySelector('.search-input-container')
  189. expect(searchInputContainer).toBeInTheDocument()
  190. const searchSections = document.querySelectorAll('.search-section')
  191. expect(searchSections.length).toBeGreaterThan(0)
  192. const searchItems = document.querySelectorAll('.search-item')
  193. expect(searchItems.length).toBeGreaterThan(0)
  194. })
  195. })
  196. })