ScheduleListPage.test.tsx 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. import React from 'react'
  2. import { render, fireEvent, waitFor } from '@testing-library/react'
  3. import { ScheduleListPage } from '../../src/pages/schedule-list/ScheduleListPage'
  4. // Mock Taro路由
  5. jest.mock('@tarojs/taro', () => ({
  6. useRouter: jest.fn(() => ({
  7. params: {
  8. startLocationId: '1',
  9. endLocationId: '2',
  10. date: '2025-10-18',
  11. vehicleType: 'bus',
  12. activityId: '101',
  13. routeType: 'departure'
  14. }
  15. })),
  16. navigateTo: jest.fn()
  17. }))
  18. // Mock API调用
  19. jest.mock('../../src/api', () => ({
  20. routeClient: {
  21. search: {
  22. $get: jest.fn().mockResolvedValue({
  23. status: 200,
  24. json: jest.fn().mockResolvedValue([
  25. {
  26. id: 1,
  27. startLocation: { name: '北京市' },
  28. endLocation: { name: '上海市' },
  29. pickupPoint: '北京首都国际机场T3航站楼',
  30. dropoffPoint: '上海虹桥机场T2航站楼',
  31. departureTime: '2025-10-18T08:00:00Z',
  32. vehicleType: 'bus',
  33. price: 120,
  34. seatCount: 40,
  35. availableSeats: 15,
  36. routeType: 'departure',
  37. activities: [
  38. { id: 101, name: '上海音乐节' },
  39. { id: 102, name: '上海艺术展' }
  40. ]
  41. },
  42. {
  43. id: 2,
  44. startLocation: { name: '北京市' },
  45. endLocation: { name: '上海市' },
  46. pickupPoint: '北京南站',
  47. dropoffPoint: '上海南站',
  48. departureTime: '2025-10-18T14:00:00Z',
  49. vehicleType: 'business',
  50. price: 200,
  51. seatCount: 7,
  52. availableSeats: 0,
  53. routeType: 'departure',
  54. activities: [
  55. { id: 101, name: '上海音乐节' }
  56. ]
  57. },
  58. {
  59. id: 3,
  60. startLocation: { name: '北京市' },
  61. endLocation: { name: '上海市' },
  62. pickupPoint: '指定地点接送',
  63. dropoffPoint: '指定地点接送',
  64. departureTime: '2025-10-18T10:00:00Z',
  65. vehicleType: 'charter',
  66. price: 800,
  67. seatCount: 15,
  68. availableSeats: 15,
  69. routeType: 'departure',
  70. activities: [
  71. { id: 101, name: '上海音乐节' }
  72. ]
  73. }
  74. ])
  75. })
  76. }
  77. }
  78. }))
  79. describe('ScheduleListPage', () => {
  80. beforeEach(() => {
  81. jest.clearAllMocks()
  82. })
  83. it('应该正确渲染页面头部信息', async () => {
  84. const { getByText } = render(<ScheduleListPage />)
  85. await waitFor(() => {
  86. expect(getByText('上海音乐节')).toBeTruthy()
  87. expect(getByText('北京市 → 上海市')).toBeTruthy()
  88. expect(getByText('去程')).toBeTruthy()
  89. })
  90. })
  91. it('应该生成日期选项', async () => {
  92. const { getByText } = render(<ScheduleListPage />)
  93. await waitFor(() => {
  94. expect(getByText('选择出发日期')).toBeTruthy()
  95. // 验证生成了7天的日期选项
  96. const today = new Date().toISOString().split('T')[0]
  97. expect(getByText(today)).toBeTruthy()
  98. })
  99. })
  100. it('应该加载并显示班次列表', async () => {
  101. const { getByText } = render(<ScheduleListPage />)
  102. await waitFor(() => {
  103. expect(getByText('可选班次')).toBeTruthy()
  104. expect(getByText('(3个班次)')).toBeTruthy()
  105. expect(getByText('08:00')).toBeTruthy()
  106. expect(getByText('14:00')).toBeTruthy()
  107. expect(getByText('10:00')).toBeTruthy()
  108. })
  109. })
  110. it('应该正确显示班次信息', async () => {
  111. const { getByText } = render(<ScheduleListPage />)
  112. await waitFor(() => {
  113. // 验证大巴拼车班次
  114. expect(getByText('¥120/人')).toBeTruthy()
  115. expect(getByText('大巴拼车')).toBeTruthy()
  116. expect(getByText('北京首都国际机场T3航站楼')).toBeTruthy()
  117. expect(getByText('上海虹桥机场T2航站楼')).toBeTruthy()
  118. expect(getByText('剩余15/40座')).toBeTruthy()
  119. // 验证商务拼车班次
  120. expect(getByText('¥200/人')).toBeTruthy()
  121. expect(getByText('商务拼车')).toBeTruthy()
  122. // 验证包车班次
  123. expect(getByText('¥800/车')).toBeTruthy()
  124. expect(getByText('包车')).toBeTruthy()
  125. expect(getByText('可载15人')).toBeTruthy()
  126. })
  127. })
  128. it('应该处理日期选择', async () => {
  129. const { getByText } = render(<ScheduleListPage />)
  130. await waitFor(() => {
  131. const newDate = '2025-10-19'
  132. const dateOption = getByText(newDate)
  133. fireEvent.click(dateOption)
  134. // 验证日期状态更新
  135. expect(dateOption.className).toContain('border-blue-500')
  136. })
  137. })
  138. it('应该处理已售罄班次', async () => {
  139. const { getByText } = render(<ScheduleListPage />)
  140. await waitFor(() => {
  141. expect(getByText('已售罄')).toBeTruthy()
  142. // 验证已售罄按钮被禁用
  143. const soldOutButton = getByText('已售罄')
  144. expect(soldOutButton.getAttribute('disabled')).toBe('')
  145. })
  146. })
  147. it('应该处理预订操作', async () => {
  148. const { getByText } = render(<ScheduleListPage />)
  149. await waitFor(() => {
  150. const bookButton = getByText('立即购票')
  151. fireEvent.click(bookButton)
  152. // 验证预订逻辑被触发
  153. // 这里可以验证控制台输出或其他副作用
  154. expect(bookButton).toBeTruthy()
  155. })
  156. })
  157. it('应该正确格式化时间和价格', async () => {
  158. const { getByText } = render(<ScheduleListPage />)
  159. await waitFor(() => {
  160. // 验证时间格式化
  161. expect(getByText('08:00')).toBeTruthy()
  162. expect(getByText('14:00')).toBeTruthy()
  163. expect(getByText('10:00')).toBeTruthy()
  164. // 验证价格格式化
  165. expect(getByText('¥120/人')).toBeTruthy()
  166. expect(getByText('¥200/人')).toBeTruthy()
  167. expect(getByText('¥800/车')).toBeTruthy()
  168. })
  169. })
  170. it('应该显示车辆类型标签', async () => {
  171. const { getByText } = render(<ScheduleListPage />)
  172. await waitFor(() => {
  173. expect(getByText('拼车')).toBeTruthy()
  174. expect(getByText('包车')).toBeTruthy()
  175. })
  176. })
  177. it('应该显示车辆特色', async () => {
  178. const { getAllByText } = render(<ScheduleListPage />)
  179. await waitFor(() => {
  180. // 验证所有班次都显示特色标签
  181. const acTags = getAllByText('空调')
  182. const wifiTags = getAllByText('免费WiFi')
  183. expect(acTags.length).toBeGreaterThan(0)
  184. expect(wifiTags.length).toBeGreaterThan(0)
  185. })
  186. })
  187. it('应该处理空班次列表', async () => {
  188. // Mock 空数据
  189. const routeClient = require('../../src/api').routeClient
  190. routeClient.search.$get.mockResolvedValueOnce({
  191. status: 200,
  192. json: jest.fn().mockResolvedValue([])
  193. })
  194. const { getByText } = render(<ScheduleListPage />)
  195. await waitFor(() => {
  196. expect(getByText('暂无班次')).toBeTruthy()
  197. expect(getByText('请选择其他日期查看')).toBeTruthy()
  198. })
  199. })
  200. it('应该正确过滤包含指定活动的路线', async () => {
  201. const { getByText } = render(<ScheduleListPage />)
  202. await waitFor(() => {
  203. // 验证只显示包含活动ID 101的路线
  204. expect(getByText('上海音乐节')).toBeTruthy()
  205. // 不应该显示包含其他活动的路线
  206. // 这里假设测试数据中所有路线都包含活动101
  207. })
  208. })
  209. it('应该处理加载状态', () => {
  210. // Mock 延迟加载
  211. const routeClient = require('../../src/api').routeClient
  212. routeClient.search.$get.mockImplementationOnce(
  213. () => new Promise(resolve => setTimeout(resolve, 100))
  214. )
  215. const { getByText } = render(<ScheduleListPage />)
  216. expect(getByText('加载中...')).toBeTruthy()
  217. })
  218. it('应该处理路由参数缺失的情况', () => {
  219. // Mock 缺失参数
  220. const useRouter = require('@tarojs/taro').useRouter
  221. useRouter.mockReturnValueOnce({
  222. params: {}
  223. })
  224. const { getByText } = render(<ScheduleListPage />)
  225. // 验证页面仍然渲染
  226. expect(getByText('选择出发日期')).toBeTruthy()
  227. })
  228. })