This commit is contained in:
2026-10-19 10:23:38 +08:00
parent 4bb21641d9
commit 8ae1e5d0d4
18 changed files with 575 additions and 28 deletions
@@ -0,0 +1,47 @@
import { beforeEach, expect, it, vi } from 'vitest'
import { shallowMount, flushPromises } from '@vue/test-utils'
import TripPickupPanel from './TripPickupPanel.vue'
import { commandPickupTask, commandPickupTrip, getPickupTasks, type PickupTask } from '../api/pickups'
import { getTrip } from '../api/trips'
import type { TripDetail } from '../tripTypes'
vi.mock('vue-router', () => ({ onBeforeRouteLeave: vi.fn() }))
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => true }) }))
vi.mock('element-plus', () => ({ ElMessage: { warning: vi.fn() }, ElMessageBox: { confirm: vi.fn().mockResolvedValue(true) } }))
vi.mock('../api/trips', () => ({ getTrip: vi.fn() }))
vi.mock('../api/pickups', () => ({ getPickupTasks: vi.fn(), commandPickupTask: vi.fn(), commandPickupTrip: vi.fn(), uploadPickupEvidence: vi.fn(), downloadPickupEvidence: vi.fn(), pickupStatusLabels: {} }))
const row: PickupTask = { customerId: 'C1', transferNo: 'WT-1', status: 'PICKED', evidence: [], lastlegOrderNo: 'LL-1', warehouseId: 'W1', pickupAddress: 'TEST Pickup Ave', contactName: '验收联系人', contactPhone: '0000000000', packageCount: 3, tripNo: 'TR-1', vehiclePlate: 'TEST-V1', driverName: '验收司机', driverPhone: '0000000000', plannedDepartureAt: null, actualPackages: 3, pickedAt: null, arrivedAt: null, remark: null }
const detail = (status: string) => ({ trip: { tripNo: 'TR-1', status, recordVersion: 2, vehicleId: 'V1', driverId: 'D1' } }) as TripDetail
function mount(status: string) {
return shallowMount(TripPickupPanel, { props: { detail: detail(status) }, global: { stubs: {
DataTable: { name: 'DataTable', props: ['data'], template: '<div><slot v-for="row in data" name="actions" :row="row"/></div>' },
ElButton: { props: ['disabled'], template: '<button :disabled="disabled"><slot/></button>' },
LoadErrorState: { name: 'LoadErrorState', emits: ['retry'], template: '<button @click="$emit(\'retry\')">重试读取</button>' },
} } })
}
beforeEach(() => { vi.clearAllMocks(); vi.mocked(getPickupTasks).mockResolvedValue([row]) })
it('locks parent actions and retries the exact departure command after an unknown result', async () => {
vi.mocked(commandPickupTrip).mockRejectedValueOnce(new Error('connection lost')).mockResolvedValueOnce(detail('IN_TRANSIT'))
const wrapper = mount('PLANNED'); await flushPromises()
await wrapper.findAll('button').find(button => button.text() === '确认取货发车')!.trigger('click'); await flushPromises()
expect(wrapper.emitted('locked')?.at(-1)).toEqual([true])
const body = vi.mocked(commandPickupTrip).mock.calls[0]![2]
await wrapper.findAll('button').find(button => button.text() === '重试原操作')!.trigger('click'); await flushPromises()
expect(vi.mocked(commandPickupTrip).mock.calls[1]![2]).toBe(body)
expect(wrapper.emitted('locked')?.at(-1)).toEqual([false])
wrapper.unmount()
})
it('retries only reading after arrival committed but the trip refresh failed', async () => {
vi.mocked(commandPickupTask).mockResolvedValue([{ ...row, status: 'ARRIVED' }])
vi.mocked(getTrip).mockRejectedValueOnce(new Error('refresh lost')).mockResolvedValueOnce(detail('IN_TRANSIT'))
const wrapper = mount('IN_TRANSIT'); await flushPromises()
await wrapper.findAll('button').find(button => button.text() === '确认送仓')!.trigger('click'); await flushPromises()
expect(commandPickupTask).toHaveBeenCalledTimes(1)
wrapper.findComponent({ name: 'LoadErrorState' }).vm.$emit('retry'); await flushPromises()
expect(commandPickupTask).toHaveBeenCalledTimes(1)
expect(getTrip).toHaveBeenCalledTimes(2)
expect(wrapper.emitted('saved')).toHaveLength(1)
wrapper.unmount()
})