Просмотр исходного кода

♻️ refactor(order): 重构toast提示为工具函数

- 创建@/utils/toast.ts封装showToast工具函数
- 将订单页面中所有Taro.showToast替换为showToast工具函数
- 优化导航返回逻辑,使用import { navigateBack }形式

✅ test(order): 完善订单页面测试用例

- 移除setup.ts中Taro.showToast的全局mock
- 在order-page.test.tsx中添加对showToast工具函数的mock
- 调整测试文件中Taro相关API的mock结构
yourname 3 месяцев назад
Родитель
Сommit
c117565bad
4 измененных файлов с 44 добавлено и 59 удалено
  1. 17 16
      mini/src/pages/order/index.tsx
  2. 15 0
      mini/src/utils/toast.ts
  3. 0 40
      mini/tests/setup.ts
  4. 12 3
      mini/tests/unit/order-page.test.tsx

+ 17 - 16
mini/src/pages/order/index.tsx

@@ -1,5 +1,5 @@
 import { View, Text, ScrollView } from '@tarojs/components'
-import Taro, { useRouter, navigateTo } from '@tarojs/taro'
+import { navigateBack, navigateTo, useRouter } from '@tarojs/taro'
 import { useState, useEffect } from 'react'
 import { useQuery, useMutation } from '@tanstack/react-query'
 import { orderClient, paymentClient, routeClient, passengerClient } from '@/api'
@@ -7,6 +7,7 @@ import { Navbar, NavbarPresets } from '@/components/ui/navbar'
 import { Button } from '@/components/ui/button'
 import { Card, CardContent } from '@/components/ui/card'
 import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'
+import { showToast } from '@/utils/toast'
 import type { InferResponseType , InferRequestType} from 'hono/client'
 import {
   requestWechatPayment,
@@ -139,14 +140,14 @@ export default function OrderPage() {
       // TODO: 实际项目中需要发送code到后端获取手机号
       setPhoneNumber('138****8888')
       setHasPhoneNumber(true)
-      Taro.showToast({
+      showToast({
         title: '手机号获取成功',
         icon: 'success',
         duration: 2000
       })
     } else {
       console.error('获取手机号失败:', e.detail.errMsg)
-      Taro.showToast({
+      showToast({
         title: '获取手机号失败,请重试',
         icon: 'error',
         duration: 2000
@@ -157,7 +158,7 @@ export default function OrderPage() {
   // 添加乘客
   const handleAddPassenger = () => {
     if (!hasPhoneNumber) {
-      Taro.showToast({
+      showToast({
         title: '请先获取手机号',
         icon: 'none',
         duration: 2000
@@ -179,7 +180,7 @@ export default function OrderPage() {
     // 检查是否已经添加过这个乘车人
     const existingPassenger = passengers.find(p => p.idNumber === passenger.idNumber)
     if (existingPassenger) {
-      Taro.showToast({
+      showToast({
         title: '该乘车人已添加',
         icon: 'none',
         duration: 2000
@@ -189,7 +190,7 @@ export default function OrderPage() {
 
     setPassengers([...passengers, passenger])
     setShowPassengerSelector(false)
-    Taro.showToast({
+    showToast({
       title: '乘客添加成功',
       icon: 'success',
       duration: 1500
@@ -202,7 +203,7 @@ export default function OrderPage() {
     const deletedPassenger = newPassengers[index]
     newPassengers.splice(index, 1)
     setPassengers(newPassengers)
-    Taro.showToast({
+    showToast({
       title: `已删除 ${deletedPassenger.name}`,
       icon: 'success',
       duration: 1500
@@ -327,7 +328,7 @@ export default function OrderPage() {
   // 创建订单并支付
   const handlePay = async () => {
     if (!hasPhoneNumber) {
-      Taro.showToast({
+      showToast({
         title: '请先获取手机号',
         icon: 'none',
         duration: 2000
@@ -336,7 +337,7 @@ export default function OrderPage() {
     }
 
     if (passengers.length === 0) {
-      Taro.showToast({
+      showToast({
         title: '请至少添加一个乘车人',
         icon: 'none',
         duration: 2000
@@ -345,7 +346,7 @@ export default function OrderPage() {
     }
 
     if (!schedule) {
-      Taro.showToast({
+      showToast({
         title: '路线数据加载中,请稍后',
         icon: 'none',
         duration: 2000
@@ -355,7 +356,7 @@ export default function OrderPage() {
     }
 
     if (!isCharter && passengers.length > (schedule.availableSeats || 0)) {
-      Taro.showToast({
+      showToast({
         title: `座位不足,最多可购买${schedule.availableSeats}张票`,
         icon: 'none',
         duration: 2000
@@ -396,7 +397,7 @@ export default function OrderPage() {
 
       if (wechatPaymentResult.success) {
         // 支付成功,跳转到支付成功页面
-        Taro.showToast({
+        showToast({
           title: '支付成功',
           icon: 'success',
           duration: 2000
@@ -408,13 +409,13 @@ export default function OrderPage() {
       } else {
         // 支付失败处理
         if (wechatPaymentResult.type === 'cancel') {
-          Taro.showToast({
+          showToast({
             title: '支付已取消',
             icon: 'none',
             duration: 2000
           })
         } else {
-          Taro.showToast({
+          showToast({
             title: wechatPaymentResult.message || '支付失败,请重试',
             icon: 'error',
             duration: 2000
@@ -427,7 +428,7 @@ export default function OrderPage() {
 
     } catch (error) {
       console.error('支付失败:', error)
-      Taro.showToast({
+      showToast({
         title: '支付失败,请重试',
         icon: 'error',
         duration: 2000
@@ -451,7 +452,7 @@ export default function OrderPage() {
       <Navbar
         title="订单确认"
         leftIcon="i-heroicons-arrow-left-20-solid"
-        onClickLeft={() => Taro.navigateBack()}
+        onClickLeft={() => navigateBack()}
         {...NavbarPresets.primary}
         data-testid="order-navbar"
       />

+ 15 - 0
mini/src/utils/toast.ts

@@ -0,0 +1,15 @@
+/**
+ * 封装的 Toast 工具函数
+ * 便于在测试环境中进行模拟
+ */
+import Taro from '@tarojs/taro'
+
+export interface ToastOptions {
+  title: string
+  icon?: 'success' | 'loading' | 'none' | 'error'
+  duration?: number
+}
+
+export const showToast = (options: ToastOptions) => {
+  Taro.showToast(options)
+}

+ 0 - 40
mini/tests/setup.ts

@@ -7,46 +7,6 @@ process.env.TARO_ENV = 'h5'
 process.env.TARO_PLATFORM = 'web'
 process.env.SUPPORT_TARO_POLYFILL = 'disabled'
 
-// Mock Taro 核心API
-const mockNavigateTo = jest.fn()
-const mockShowToast = jest.fn()
-const mockRequestPayment = jest.fn()
-const mockNavigateBack = jest.fn()
-
-jest.mock('@tarojs/taro', () => ({
-  __esModule: true,
-  default: {
-    getEnv: () => 'WEB',
-    ENV_TYPE: {
-      WEAPP: 'WEAPP',
-      WEB: 'WEB'
-    },
-    getSystemInfoSync: () => ({
-      statusBarHeight: 44,
-      screenWidth: 375,
-      screenHeight: 667,
-      windowWidth: 375,
-      windowHeight: 603,
-      pixelRatio: 2
-    }),
-    getMenuButtonBoundingClientRect: () => ({
-      width: 87,
-      height: 32,
-      top: 48,
-      right: 314,
-      bottom: 80,
-      left: 227
-    }),
-    navigateBack: mockNavigateBack,
-    requestPayment: mockRequestPayment
-  },
-  useRouter: () => ({
-    params: {}
-  }),
-  navigateTo: mockNavigateTo,
-  showToast: mockShowToast
-}))
-
 // Mock Taro 组件
 // eslint-disable-next-line react/display-name
 jest.mock('@tarojs/components', () => {

+ 12 - 3
mini/tests/unit/order-page.test.tsx

@@ -2,19 +2,19 @@
  * 订单页面组件测试
  */
 
-import React from 'react'
 import { render, screen, fireEvent, waitFor } from '@testing-library/react'
 import '@testing-library/jest-dom'
 import OrderPage from '@/pages/order/index'
 
 // Mock Taro相关API
 const mockNavigateTo = jest.fn()
-const mockShowToast = jest.fn()
 const mockUseRouter = jest.fn()
 
+// Mock 封装的 toast 函数
+let mockShowToast: jest.Mock
+
 jest.mock('@tarojs/taro', () => ({
   navigateBack: jest.fn(),
-  showToast: mockShowToast,
   useRouter: () => mockUseRouter(),
   navigateTo: mockNavigateTo,
   requestPayment: jest.fn(),
@@ -31,6 +31,15 @@ jest.mock('@tarojs/taro', () => ({
   })
 }))
 
+// Mock 封装的 toast 工具函数
+jest.mock('@/utils/toast', () => ({
+  showToast: jest.fn()
+}))
+
+beforeAll(() => {
+  mockShowToast = require('@/utils/toast').showToast
+})
+
 // Mock React Query
 const mockUseQuery = jest.fn()
 const mockUseMutation = jest.fn()