| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672 |
- import React from 'react'
- import { render, screen, waitFor } from '@testing-library/react'
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
- import ScheduleListPage from '../../src/pages/schedule-list/ScheduleListPage'
- // Mock Taro API
- jest.mock('@tarojs/taro', () => ({
- useRouter: jest.fn(() => ({
- params: {
- startAreaIds: JSON.stringify([1, 2]),
- endAreaIds: JSON.stringify([3, 4]),
- startAreaName: '',
- endAreaName: '',
- date: '2025-10-31',
- vehicleType: 'bus',
- travelMode: 'carpool',
- activityId: '1',
- routeType: 'departure'
- }
- })),
- navigateTo: jest.fn(),
- navigateBack: jest.fn()
- }))
- // Mock API client
- jest.mock('../../src/api', () => ({
- routeClient: {
- search: {
- $get: jest.fn(() => Promise.resolve({
- status: 200,
- json: () => Promise.resolve({
- data: {
- routes: [
- {
- id: 1,
- name: '测试路线',
- description: null,
- startLocationId: 1,
- endLocationId: 2,
- startLocation: {
- id: 1,
- name: '起点',
- provinceId: 1,
- cityId: 1,
- districtId: 1,
- address: '起点地址'
- },
- endLocation: {
- id: 2,
- name: '终点',
- provinceId: 2,
- cityId: 2,
- districtId: 2,
- address: '终点地址'
- },
- pickupPoint: '上车点',
- dropoffPoint: '下车点',
- departureTime: '2025-10-31T08:00:00Z',
- vehicleType: 'bus',
- travelMode: 'carpool',
- price: 100,
- seatCount: 40,
- availableSeats: 20,
- activityId: 1,
- activity: {
- id: 1,
- name: '测试活动',
- description: null,
- venueLocationId: 3,
- venueLocation: {
- id: 3,
- name: '活动场地',
- provinceId: 3,
- cityId: 3,
- districtId: 3,
- address: '活动场地地址'
- },
- startDate: '2025-10-31',
- endDate: '2025-11-01'
- },
- routeType: 'departure',
- isDisabled: 0,
- isDeleted: 0,
- createdAt: '2025-10-31T00:00:00Z',
- updatedAt: '2025-10-31T00:00:00Z'
- }
- ],
- activities: [
- {
- id: 1,
- name: '测试活动',
- description: null,
- venueLocationId: 3,
- venueLocation: {
- id: 3,
- name: '活动场地',
- provinceId: 3,
- cityId: 3,
- districtId: 3,
- address: '活动场地地址'
- },
- startDate: '2025-10-31',
- endDate: '2025-11-01'
- }
- ]
- }
- })
- }))
- }
- }
- }))
- // Mock date-fns
- jest.mock('date-fns', () => ({
- format: jest.fn(() => '08:00'),
- zhCN: {}
- }))
- // Mock components
- jest.mock('../../src/components/ui/navbar', () => ({
- Navbar: ({ title, onClickLeft }: { title: string; onClickLeft: () => void }) => (
- <div data-testid="navbar">
- <div>{title}</div>
- <button onClick={onClickLeft}>返回</button>
- </div>
- ),
- NavbarPresets: {
- primary: {}
- }
- }))
- const createTestQueryClient = () => new QueryClient({
- defaultOptions: {
- queries: { retry: false },
- },
- })
- const Wrapper = ({ children }: { children: React.ReactNode }) => (
- <QueryClientProvider client={createTestQueryClient()}>
- {children}
- </QueryClientProvider>
- )
- describe('ScheduleListPage', () => {
- beforeEach(() => {
- jest.clearAllMocks()
- })
- test('应该正确渲染班次页面', async () => {
- render(
- <Wrapper>
- <ScheduleListPage />
- </Wrapper>
- )
- // 等待数据加载
- await waitFor(() => {
- expect(screen.getByText('选择班次')).toBeInTheDocument()
- })
- // 验证页面标题
- expect(screen.getByText('选择班次')).toBeInTheDocument()
- // 验证活动名称显示
- expect(screen.getByText('测试活动')).toBeInTheDocument()
- // 验证路线信息显示 - 起点使用地点名称,终点保持不变
- expect(screen.getByText('起点 → 终点')).toBeInTheDocument()
- expect(screen.getByText('去程')).toBeInTheDocument()
- // 验证班次列表显示
- expect(screen.getByText('可选班次')).toBeInTheDocument()
- expect(screen.getByText('(1个班次)')).toBeInTheDocument()
- // 验证班次详情显示
- expect(screen.getByText('08:00')).toBeInTheDocument()
- expect(screen.getByText('¥100/人')).toBeInTheDocument()
- expect(screen.getByText('大巴拼车')).toBeInTheDocument()
- expect(screen.getByText('拼车')).toBeInTheDocument()
- expect(screen.getByText('上车点')).toBeInTheDocument()
- expect(screen.getByText('下车点')).toBeInTheDocument()
- expect(screen.getByText('剩余20/40座')).toBeInTheDocument()
- expect(screen.getByText('空调')).toBeInTheDocument()
- expect(screen.getByText('免费WiFi')).toBeInTheDocument()
- // 验证预订按钮
- expect(screen.getByText('立即购票')).toBeInTheDocument()
- })
- test('应该隐藏日期选择功能', async () => {
- render(
- <Wrapper>
- <ScheduleListPage />
- </Wrapper>
- )
- // 等待数据加载
- await waitFor(() => {
- expect(screen.getByText('选择班次')).toBeInTheDocument()
- })
- // 验证日期选择UI组件已隐藏
- // 不应该显示"选择出发日期"文本
- const dateSelectionText = screen.queryByText('选择出发日期')
- expect(dateSelectionText).not.toBeInTheDocument()
- // 不应该显示日期选项
- const dateOptions = screen.queryByText('2025-10-31')
- expect(dateOptions).not.toBeInTheDocument()
- })
- test('应该显示加载状态', () => {
- // Mock loading state
- const mockApi = require('../../src/api')
- mockApi.routeClient.search.$get.mockImplementationOnce(
- () => new Promise(() => {}) // Never resolves to simulate loading
- )
- render(
- <Wrapper>
- <ScheduleListPage />
- </Wrapper>
- )
- expect(screen.getByText('加载中...')).toBeInTheDocument()
- })
- test('应该显示无班次状态', async () => {
- // Mock empty data
- const mockApi = require('../../src/api')
- mockApi.routeClient.search.$get.mockResolvedValueOnce({
- status: 200,
- json: () => Promise.resolve({
- data: {
- routes: [],
- activities: []
- }
- })
- })
- render(
- <Wrapper>
- <ScheduleListPage />
- </Wrapper>
- )
- await waitFor(() => {
- expect(screen.getByText('暂无班次')).toBeInTheDocument()
- })
- expect(screen.getByText('当前选择的路线暂无可用班次,请返回重新选择路线')).toBeInTheDocument()
- })
- test('应该在没有省市区名称时使用默认值', async () => {
- // Mock router without area names
- const mockTaro = require('@tarojs/taro')
- mockTaro.useRouter.mockImplementationOnce(() => ({
- params: {
- startAreaIds: JSON.stringify([1, 2]),
- endAreaIds: JSON.stringify([3, 4]),
- date: '2025-10-31',
- vehicleType: 'bus',
- travelMode: 'carpool',
- activityId: '1',
- routeType: 'departure'
- }
- }))
- render(
- <Wrapper>
- <ScheduleListPage />
- </Wrapper>
- )
- await waitFor(() => {
- expect(screen.getByText('选择班次')).toBeInTheDocument()
- })
- // 应该显示路线数据中的起点名称和终点名称
- expect(screen.getByText('起点 → 终点')).toBeInTheDocument()
- })
- test('应该优先使用路由参数中的省市区名称', async () => {
- // Mock router with custom area names
- const mockTaro = require('@tarojs/taro')
- mockTaro.useRouter.mockImplementation(() => ({
- params: {
- startAreaIds: JSON.stringify([1, 2]),
- endAreaIds: JSON.stringify([3, 4]),
- startAreaName: encodeURIComponent('北京市 朝阳区'),
- date: '2025-10-31',
- vehicleType: 'bus',
- travelMode: 'carpool',
- activityId: '1',
- routeType: 'departure'
- }
- }))
- // Mock empty route data
- const mockApi = require('../../src/api')
- mockApi.routeClient.search.$get.mockImplementation(() => Promise.resolve({
- status: 200,
- json: () => Promise.resolve({
- data: {
- routes: [],
- activities: []
- }
- })
- }))
- render(
- <Wrapper>
- <ScheduleListPage />
- </Wrapper>
- )
- await waitFor(() => {
- expect(screen.getByText('选择班次')).toBeInTheDocument()
- })
- // 等待数据加载完成,确保显示正确的内容
- await waitFor(() => {
- expect(screen.getByText('暂无班次')).toBeInTheDocument()
- })
- // 检查地区名称显示 - 等待组件渲染完成
- await waitFor(() => {
- const areaDisplay = screen.getByTestId('area-display')
- expect(areaDisplay).toHaveTextContent('请选择路线 → 请选择路线')
- }, { timeout: 5000 })
- })
- test('应该在没有路线数据时显示默认地区信息', async () => {
- // Mock empty data and no area names
- const mockTaro = require('@tarojs/taro')
- mockTaro.useRouter.mockImplementationOnce(() => ({
- params: {
- startAreaIds: JSON.stringify([1, 2]),
- endAreaIds: JSON.stringify([3, 4]),
- date: '2025-10-31',
- vehicleType: 'bus',
- travelMode: 'carpool',
- activityId: '1',
- routeType: 'departure'
- }
- }))
- const mockApi = require('../../src/api')
- mockApi.routeClient.search.$get.mockResolvedValueOnce({
- status: 200,
- json: () => Promise.resolve({
- data: {
- routes: [],
- activities: []
- }
- })
- })
- render(
- <Wrapper>
- <ScheduleListPage />
- </Wrapper>
- )
- await waitFor(() => {
- expect(screen.getByText('暂无班次')).toBeInTheDocument()
- })
- // 应该显示默认的起点名称和终点名称
- expect(screen.getByText('请选择路线 → 请选择路线')).toBeInTheDocument()
- })
- test('去程路线应该优化起点显示为省市区格式', async () => {
- // Mock router with area names for departure route
- const mockTaro = require('@tarojs/taro')
- mockTaro.useRouter.mockImplementation(() => ({
- params: {
- startAreaIds: JSON.stringify([1, 2]),
- endAreaIds: JSON.stringify([3, 4]),
- startAreaName: encodeURIComponent('广东省 广州市 市辖区'),
- endAreaName: '',
- date: '2025-10-31',
- vehicleType: 'bus',
- travelMode: 'carpool',
- activityId: '1',
- routeType: 'departure'
- }
- }))
- // Mock API to return departure route data
- const mockApi = require('../../src/api')
- mockApi.routeClient.search.$get.mockImplementation(() => Promise.resolve({
- status: 200,
- json: () => Promise.resolve({
- data: {
- routes: [
- {
- id: 1,
- name: '测试路线',
- description: null,
- startLocationId: 1,
- endLocationId: 2,
- startLocation: {
- id: 1,
- name: '起点',
- provinceId: 1,
- cityId: 1,
- districtId: 1,
- address: '起点地址'
- },
- endLocation: {
- id: 2,
- name: '终点',
- provinceId: 2,
- cityId: 2,
- districtId: 2,
- address: '终点地址'
- },
- pickupPoint: '上车点',
- dropoffPoint: '下车点',
- departureTime: '2025-10-31T08:00:00Z',
- vehicleType: 'bus',
- travelMode: 'carpool',
- price: 100,
- seatCount: 40,
- availableSeats: 20,
- activityId: 1,
- activity: {
- id: 1,
- name: '测试活动',
- description: null,
- venueLocationId: 3,
- venueLocation: {
- id: 3,
- name: '活动场地',
- provinceId: 3,
- cityId: 3,
- districtId: 3,
- address: '活动场地地址'
- },
- startDate: '2025-10-31',
- endDate: '2025-11-01'
- },
- routeType: 'departure',
- isDisabled: 0,
- isDeleted: 0,
- createdAt: '2025-10-31T00:00:00Z',
- updatedAt: '2025-10-31T00:00:00Z'
- }
- ],
- activities: [
- {
- id: 1,
- name: '测试活动',
- description: null,
- venueLocationId: 3,
- venueLocation: {
- id: 3,
- name: '活动场地',
- provinceId: 3,
- cityId: 3,
- districtId: 3,
- address: '活动场地地址'
- },
- startDate: '2025-10-31',
- endDate: '2025-11-01'
- }
- ]
- }
- })
- }))
- render(
- <Wrapper>
- <ScheduleListPage />
- </Wrapper>
- )
- await waitFor(() => {
- expect(screen.getByText('选择班次')).toBeInTheDocument()
- })
- // 去程路线:应该显示"搜索起点 省份 城市 区县 → 路线终点地点名称"格式
- expect(screen.getByText('广东省 广州市 市辖区 → 终点')).toBeInTheDocument()
- })
- test('返程路线应该优化终点显示为省市区格式', async () => {
- // Mock router with area names for return route
- const mockTaro = require('@tarojs/taro')
- mockTaro.useRouter.mockImplementation(() => ({
- params: {
- startAreaIds: JSON.stringify([1, 2]),
- endAreaIds: JSON.stringify([3, 4]),
- startAreaName: encodeURIComponent('广东省 广州市 市辖区'),
- date: '2025-10-31',
- vehicleType: 'bus',
- travelMode: 'carpool',
- activityId: '1',
- routeType: 'return'
- }
- }))
- // Mock API to return return route data
- const mockApi = require('../../src/api')
- mockApi.routeClient.search.$get.mockImplementation(() => Promise.resolve({
- status: 200,
- json: () => Promise.resolve({
- data: {
- routes: [
- {
- id: 1,
- name: '测试路线',
- description: null,
- startLocationId: 1,
- endLocationId: 2,
- startLocation: {
- id: 1,
- name: '起点',
- provinceId: 1,
- cityId: 1,
- districtId: 1,
- address: '起点地址'
- },
- endLocation: {
- id: 2,
- name: '终点',
- provinceId: 2,
- cityId: 2,
- districtId: 2,
- address: '终点地址'
- },
- pickupPoint: '上车点',
- dropoffPoint: '下车点',
- departureTime: '2025-10-31T08:00:00Z',
- vehicleType: 'bus',
- travelMode: 'carpool',
- price: 100,
- seatCount: 40,
- availableSeats: 20,
- activityId: 1,
- activity: {
- id: 1,
- name: '测试活动',
- description: null,
- venueLocationId: 3,
- venueLocation: {
- id: 3,
- name: '活动场地',
- provinceId: 3,
- cityId: 3,
- districtId: 3,
- address: '活动场地地址'
- },
- startDate: '2025-10-31',
- endDate: '2025-11-01'
- },
- routeType: 'return',
- isDisabled: 0,
- isDeleted: 0,
- createdAt: '2025-10-31T00:00:00Z',
- updatedAt: '2025-10-31T00:00:00Z'
- }
- ],
- activities: [
- {
- id: 1,
- name: '测试活动',
- description: null,
- venueLocationId: 3,
- venueLocation: {
- id: 3,
- name: '活动场地',
- provinceId: 3,
- cityId: 3,
- districtId: 3,
- address: '活动场地地址'
- },
- startDate: '2025-10-31',
- endDate: '2025-11-01'
- }
- ]
- }
- })
- }))
- render(
- <Wrapper>
- <ScheduleListPage />
- </Wrapper>
- )
- await waitFor(() => {
- expect(screen.getByText('选择班次')).toBeInTheDocument()
- })
- // 返程路线:应该显示"路线起点地点名称 → 搜索起点 省份 城市 区县"格式
- expect(screen.getByText('起点 → 广东省 广州市 市辖区')).toBeInTheDocument()
- })
- test('页面加载时不应该默认选择路线', async () => {
- // Mock router with no route data
- const mockTaro = require('@tarojs/taro')
- mockTaro.useRouter.mockImplementationOnce(() => ({
- params: {
- startAreaIds: JSON.stringify([1, 2]),
- endAreaIds: JSON.stringify([3, 4]),
- date: '2025-10-31',
- vehicleType: 'bus',
- travelMode: 'carpool',
- activityId: '1',
- routeType: 'departure'
- }
- }))
- const mockApi = require('../../src/api')
- mockApi.routeClient.search.$get.mockResolvedValueOnce({
- status: 200,
- json: () => Promise.resolve({
- data: {
- routes: [],
- activities: []
- }
- })
- })
- render(
- <Wrapper>
- <ScheduleListPage />
- </Wrapper>
- )
- await waitFor(() => {
- expect(screen.getByText('暂无班次')).toBeInTheDocument()
- })
- // 应该显示"请选择路线"而不是默认的路线信息
- expect(screen.getByText('请选择路线 → 请选择路线')).toBeInTheDocument()
- expect(screen.getByText('当前选择的路线暂无可用班次,请返回重新选择路线')).toBeInTheDocument()
- })
- test('应该正确处理省市区信息从路由参数传递', async () => {
- // Mock router with complete area information
- const mockTaro = require('@tarojs/taro')
- mockTaro.useRouter.mockImplementation(() => ({
- params: {
- startAreaIds: JSON.stringify([1, 2]),
- endAreaIds: JSON.stringify([3, 4]),
- startAreaName: encodeURIComponent('北京市 朝阳区'),
- endAreaName: encodeURIComponent('上海市 浦东新区'),
- date: '2025-10-31',
- vehicleType: 'bus',
- travelMode: 'carpool',
- activityId: '1',
- routeType: 'departure'
- }
- }))
- render(
- <Wrapper>
- <ScheduleListPage />
- </Wrapper>
- )
- await waitFor(() => {
- expect(screen.getByText('选择班次')).toBeInTheDocument()
- })
- // 应该正确显示从路由参数传递的省市区信息
- // 去程路线:显示搜索起点省市区到路线终点地点名称
- expect(screen.getByText('北京市 朝阳区 → 终点')).toBeInTheDocument()
- })
- })
|