Files
admin-web/src/modules/overseas-master-data/components/PickupDemandPanel.test.ts
T
2026-10-19 10:23:38 +08:00

50 lines
3.9 KiB
TypeScript

import { afterEach, beforeEach, expect, it, vi } from 'vitest'
import { shallowMount, flushPromises, type VueWrapper } from '@vue/test-utils'
import PickupDemandPanel from './PickupDemandPanel.vue'
import { listPickupCandidates, createPickupTrip, type PickupCandidate } from '../api/pickups'
import type { TripDetail } from '../tripTypes'
const state = vi.hoisted(() => ({ push: vi.fn(), write: true }))
vi.mock('vue-router', () => ({ useRouter: () => ({ push: state.push }), onBeforeRouteLeave: vi.fn() }))
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => state.write }) }))
vi.mock('element-plus', () => ({ ElMessage: { warning: vi.fn() } }))
vi.mock('../api/pickups', () => ({ listPickupCandidates: vi.fn(), createPickupTrip: vi.fn() }))
const rows: PickupCandidate[] = [1, 2].map(i => ({ customerId: `C${i}`, transferNo: `WT-${i}`, lastlegOrderNo: `LL-${i}`, warehouseId: '9007199254740999', pickupAddress: `TEST Ontario ${i}`, contactName: '取货验收员', contactPhone: '000', packageCount: 5, expectedArrivalAt: null }))
const wrappers: VueWrapper[] = []
function mount() {
const wrapper = shallowMount(PickupDemandPanel, { global: { stubs: {
DataTable: { name: 'DataTable', props: ['data', 'total'], emits: ['selection-change'], template: '<div><slot name="toolbar-actions"/><slot name="notices"/></div>' },
AppDialog: { name: 'AppDialog', props: ['modelValue'], emits: ['confirm'], template: '<div v-if="modelValue"><slot/></div>' },
ElButton: { props: ['disabled'], template: '<button :disabled="disabled"><slot/></button>' },
ElForm: { template: '<div><slot/></div>' }, ElFormItem: { template: '<div><slot/></div>' },
ElDatePicker: { name: 'ElDatePicker', props: ['modelValue'], emits: ['update:modelValue'], template: '<input />' },
} } }); wrappers.push(wrapper); return wrapper
}
beforeEach(() => { vi.clearAllMocks(); state.write = true; vi.mocked(listPickupCandidates).mockResolvedValue({ records: rows, total: 42 }) })
afterEach(() => wrappers.splice(0).forEach(wrapper => wrapper.unmount()))
it('uses server total and rejects combining different destination warehouses', async () => {
const wrapper = mount(); await flushPromises()
expect(wrapper.findComponent({ name: 'DataTable' }).props('total')).toBe(42)
wrapper.findComponent({ name: 'DataTable' }).vm.$emit('selection-change', [rows[0], { ...rows[1], warehouseId: 'OTHER' }]); await flushPromises()
await wrapper.find('button').trigger('click')
expect(wrapper.findComponent({ name: 'AppDialog' }).props('modelValue')).toBe(false)
expect(createPickupTrip).not.toHaveBeenCalled()
})
it('keeps exact source identities and the same create request after an unknown network result', async () => {
const wrapper = mount(); await flushPromises()
wrapper.findComponent({ name: 'DataTable' }).vm.$emit('selection-change', rows); await flushPromises(); await wrapper.find('button').trigger('click')
const dates = wrapper.findAllComponents({ name: 'ElDatePicker' })
dates[0]!.vm.$emit('update:modelValue', '2026-10-17T08:00:00Z'); dates[1]!.vm.$emit('update:modelValue', '2026-10-18T08:00:00Z'); await flushPromises()
vi.mocked(createPickupTrip).mockRejectedValueOnce(new Error('connection lost')).mockResolvedValueOnce({ trip: { tripNo: 'TR-TEST' } } as TripDetail)
const dialog = wrapper.findComponent({ name: 'AppDialog' }); dialog.vm.$emit('confirm'); await flushPromises()
const request = vi.mocked(createPickupTrip).mock.calls[0]![0]
expect(request.sources).toEqual(rows.map(({ customerId, transferNo }) => ({ customerId, transferNo })))
dialog.vm.$emit('confirm'); await flushPromises()
expect(vi.mocked(createPickupTrip).mock.calls[1]![0]).toBe(request)
expect(state.push).toHaveBeenCalledWith({ name: 'overseas-master-data-trip-detail', params: { tripNo: 'TR-TEST' } })
})
it('does not show scheduling to read-only users', async () => {
state.write = false; const wrapper = mount(); await flushPromises()
expect(wrapper.find('button').exists()).toBe(false)
})