|
|
@@ -0,0 +1,299 @@
|
|
|
+/**
|
|
|
+ * 订单详情页面组件测试
|
|
|
+ */
|
|
|
+
|
|
|
+import React from 'react'
|
|
|
+import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
|
|
+import '@testing-library/jest-dom'
|
|
|
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
|
+import OrderDetailPage from '@/pages/order-detail/index'
|
|
|
+
|
|
|
+// 导入 Taro mock 函数
|
|
|
+import taroMock, { mockUseRouter, mockGetCurrentInstance } from '../../tests/__mocks__/taroMock'
|
|
|
+
|
|
|
+// Mock React Query
|
|
|
+const mockUseQuery = jest.fn()
|
|
|
+const mockUseMutation = jest.fn()
|
|
|
+
|
|
|
+// Mock React Query
|
|
|
+jest.mock('@tanstack/react-query', () => {
|
|
|
+ const actual = jest.requireActual('@tanstack/react-query')
|
|
|
+ return {
|
|
|
+ ...actual,
|
|
|
+ useQuery: (options: any) => mockUseQuery(options),
|
|
|
+ useMutation: (options: any) => mockUseMutation(options)
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 创建测试用的 QueryClient
|
|
|
+const createTestQueryClient = () => new QueryClient({
|
|
|
+ defaultOptions: {
|
|
|
+ queries: {
|
|
|
+ retry: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+})
|
|
|
+
|
|
|
+// 包装组件
|
|
|
+const Wrapper = ({ children }: { children: React.ReactNode }) => {
|
|
|
+ const queryClient = createTestQueryClient()
|
|
|
+ return (
|
|
|
+ <QueryClientProvider client={queryClient}>
|
|
|
+ {children}
|
|
|
+ </QueryClientProvider>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+// Mock API客户端
|
|
|
+jest.mock('@/api', () => ({
|
|
|
+ orderClient: {
|
|
|
+ ':id': {
|
|
|
+ $get: jest.fn(),
|
|
|
+ cancel: {
|
|
|
+ $post: jest.fn()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}))
|
|
|
+
|
|
|
+describe('OrderDetailPage', () => {
|
|
|
+ const mockOrderData = {
|
|
|
+ id: 123,
|
|
|
+ status: 'WAITING_DEPARTURE',
|
|
|
+ paymentStatus: 'PAID',
|
|
|
+ passengerCount: 2,
|
|
|
+ totalAmount: 200,
|
|
|
+ createdAt: '2025-10-24 10:00:00',
|
|
|
+ routeSnapshot: {
|
|
|
+ name: '测试路线',
|
|
|
+ pickupPoint: '上车地点',
|
|
|
+ dropoffPoint: '下车地点',
|
|
|
+ departureTime: '2025-10-24 10:00:00',
|
|
|
+ vehicleType: '商务车',
|
|
|
+ travelMode: 'charter',
|
|
|
+ price: 100
|
|
|
+ },
|
|
|
+ passengerSnapshots: [
|
|
|
+ {
|
|
|
+ name: '张三',
|
|
|
+ idType: '身份证',
|
|
|
+ idNumber: '110101199001011234',
|
|
|
+ phone: '13800138000'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '李四',
|
|
|
+ idType: '身份证',
|
|
|
+ idNumber: '110101199001011235',
|
|
|
+ phone: '13800138001'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+
|
|
|
+ beforeEach(() => {
|
|
|
+ jest.clearAllMocks()
|
|
|
+
|
|
|
+ // Mock Taro.getCurrentInstance
|
|
|
+ taroMock.getCurrentInstance.mockReturnValue({
|
|
|
+ router: {
|
|
|
+ params: {
|
|
|
+ id: '123'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ mockUseQuery.mockImplementation((options) => {
|
|
|
+ if (options.queryKey?.[0] === 'order') {
|
|
|
+ return {
|
|
|
+ data: mockOrderData,
|
|
|
+ isLoading: false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return { data: null, isLoading: false }
|
|
|
+ })
|
|
|
+
|
|
|
+ mockUseMutation.mockImplementation((options) => ({
|
|
|
+ mutateAsync: options.mutationFn,
|
|
|
+ isPending: false
|
|
|
+ }))
|
|
|
+
|
|
|
+ // 重置所有 Taro mock 调用记录
|
|
|
+ taroMock.showToast.mockClear()
|
|
|
+ taroMock.showModal.mockClear()
|
|
|
+ taroMock.navigateBack.mockClear()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should render order detail page correctly', () => {
|
|
|
+ render(
|
|
|
+ <Wrapper>
|
|
|
+ <OrderDetailPage />
|
|
|
+ </Wrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(screen.getByText('订单详情')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('订单信息')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('123')).toBeInTheDocument() // 订单号
|
|
|
+ expect(screen.getByText('上车地点 → 下车地点')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should display departure time as customer service confirmation message', () => {
|
|
|
+ render(
|
|
|
+ <Wrapper>
|
|
|
+ <OrderDetailPage />
|
|
|
+ </Wrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ // 验证出发时间显示为"客服将与您沟通确认"
|
|
|
+ const departureTimeElement = screen.getByTestId('departure-time')
|
|
|
+ expect(departureTimeElement).toBeInTheDocument()
|
|
|
+ expect(departureTimeElement).toHaveTextContent('客服将与您沟通确认')
|
|
|
+
|
|
|
+ // 验证其他订单信息正常显示
|
|
|
+ expect(screen.getByText('车辆型号:')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('乘车人数:')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('订单状态:')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('支付状态:')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('订单金额:')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('下单时间:')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should show loading state', () => {
|
|
|
+ mockUseQuery.mockImplementation((options) => {
|
|
|
+ if (options.queryKey?.[0] === 'order') {
|
|
|
+ return { data: null, isLoading: true }
|
|
|
+ }
|
|
|
+ return { data: null, isLoading: false }
|
|
|
+ })
|
|
|
+
|
|
|
+ render(
|
|
|
+ <Wrapper>
|
|
|
+ <OrderDetailPage />
|
|
|
+ </Wrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(screen.getByText('加载中...')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ it.skip('should handle order cancellation', async () => {
|
|
|
+ render(
|
|
|
+ <Wrapper>
|
|
|
+ <OrderDetailPage />
|
|
|
+ </Wrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ // 验证取消订单按钮存在
|
|
|
+ const cancelButton = screen.getByTestId('cancel-order-button')
|
|
|
+ expect(cancelButton).toBeInTheDocument()
|
|
|
+
|
|
|
+ // 点击取消订单按钮
|
|
|
+ fireEvent.click(cancelButton)
|
|
|
+
|
|
|
+ // 应该显示确认对话框
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(taroMock.showModal).toHaveBeenCalledWith({
|
|
|
+ title: '确认取消订单',
|
|
|
+ content: '取消后将无法恢复,确定要取消这个订单吗?',
|
|
|
+ confirmText: '确认取消',
|
|
|
+ cancelText: '再想想',
|
|
|
+ confirmColor: '#ff4d4f',
|
|
|
+ success: expect.any(Function)
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should display passenger information', () => {
|
|
|
+ render(
|
|
|
+ <Wrapper>
|
|
|
+ <OrderDetailPage />
|
|
|
+ </Wrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ // 验证乘客信息显示
|
|
|
+ expect(screen.getByText('乘客信息')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('张三')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('李四')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('110101199001011234')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('110101199001011235')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should display route snapshot information', () => {
|
|
|
+ render(
|
|
|
+ <Wrapper>
|
|
|
+ <OrderDetailPage />
|
|
|
+ </Wrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ // 验证路线快照信息显示
|
|
|
+ expect(screen.getByText('行程详情')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('测试路线')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('¥100')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should handle error state', () => {
|
|
|
+ mockUseQuery.mockImplementation((options) => {
|
|
|
+ if (options.queryKey?.[0] === 'order') {
|
|
|
+ return {
|
|
|
+ data: null,
|
|
|
+ isLoading: false,
|
|
|
+ error: new Error('获取订单详情失败')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return { data: null, isLoading: false }
|
|
|
+ })
|
|
|
+
|
|
|
+ render(
|
|
|
+ <Wrapper>
|
|
|
+ <OrderDetailPage />
|
|
|
+ </Wrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(screen.getByText('加载失败')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('返回')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should handle missing order id', () => {
|
|
|
+ // Mock 没有订单ID的情况
|
|
|
+ taroMock.getCurrentInstance.mockReturnValue({
|
|
|
+ router: {
|
|
|
+ params: {}
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ mockUseQuery.mockImplementation((options) => {
|
|
|
+ if (options.queryKey?.[0] === 'order') {
|
|
|
+ return {
|
|
|
+ data: null,
|
|
|
+ isLoading: false,
|
|
|
+ error: new Error('订单ID不存在')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return { data: null, isLoading: false }
|
|
|
+ })
|
|
|
+
|
|
|
+ render(
|
|
|
+ <Wrapper>
|
|
|
+ <OrderDetailPage />
|
|
|
+ </Wrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(screen.getByText('加载失败')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should apply time display optimization consistently', () => {
|
|
|
+ render(
|
|
|
+ <Wrapper>
|
|
|
+ <OrderDetailPage />
|
|
|
+ </Wrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ // 验证出发时间显示优化已应用
|
|
|
+ const departureTimeElement = screen.getByTestId('departure-time')
|
|
|
+ expect(departureTimeElement).toBeInTheDocument()
|
|
|
+ expect(departureTimeElement).toHaveTextContent('客服将与您沟通确认')
|
|
|
+
|
|
|
+ // 验证其他信息正常显示
|
|
|
+ expect(screen.getByText('车辆型号:')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('乘车人数:')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('2人')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('¥200')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+})
|