import { afterEach, beforeEach, expect, it, vi } from 'vitest'
import { shallowMount, flushPromises, type VueWrapper } from '@vue/test-utils'
import VehicleFulfillmentTable from './VehicleFulfillmentTable.vue'
import * as api from '../api/vehicleFulfillment'
const permissions = vi.hoisted(() => ({ allowed: true }))
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => permissions.allowed }) }))
vi.mock('../api/vehicleFulfillment', () => ({ listVehicleDeliveries: vi.fn(), listVehicleAssignmentChanges: vi.fn() }))
const wrappers: VueWrapper[] = []
const result = (number: string) => ({ records: [{ deliveryNo: number }], page: 1, size: 10, total: 1, pages: 1 })
function mount(kind: 'deliveries' | 'changes' = 'deliveries') {
const wrapper = shallowMount(VehicleFulfillmentTable, { props: { vehicleId: '900719925474099301', kind }, global: { stubs: {
DataTable: { name: 'DataTable', props: ['data','columns','page','pageSize','total','loading'], emits: ['update:page','update:pageSize'], template: '
' },
ElButton: { template: '' }, LoadErrorState: { name: 'LoadErrorState', props: ['message'], template: '{{ message }}
' }, ApiErrorMeta: true,
} } }); wrappers.push(wrapper); return wrapper
}
beforeEach(() => {
vi.clearAllMocks(); permissions.allowed = true
vi.mocked(api.listVehicleDeliveries).mockResolvedValue(result('DL-1') as Awaited>)
vi.mocked(api.listVehicleAssignmentChanges).mockResolvedValue({ records: [], page: 1, size: 10, total: 0, pages: 0 })
})
afterEach(() => { wrappers.splice(0).forEach(w => w.unmount()) })
it('loads only its displayed projection once and does not fetch per-row details', async () => {
const wrapper = mount(); await flushPromises()
expect(api.listVehicleDeliveries).toHaveBeenCalledExactlyOnceWith('900719925474099301',1,10)
expect(api.listVehicleAssignmentChanges).not.toHaveBeenCalled()
expect(wrapper.findComponent({ name: 'DataTable' }).props('data')).toEqual(result('DL-1').records)
})
it('does not call either endpoint without the required viewing permissions', async () => {
permissions.allowed = false; const wrapper = mount(); await flushPromises()
expect(api.listVehicleDeliveries).not.toHaveBeenCalled(); expect(api.listVehicleAssignmentChanges).not.toHaveBeenCalled()
expect(wrapper.text()).toContain('暂无派送记录查看权限')
})
it('changing vehicle from a later page resets pagination and sends one scoped request', async () => {
const wrapper = mount(); await flushPromises()
wrapper.findComponent({ name: 'DataTable' }).vm.$emit('update:page', 3); await flushPromises()
vi.mocked(api.listVehicleDeliveries).mockClear()
await wrapper.setProps({ vehicleId: '900719925474099302' }); await flushPromises()
expect(api.listVehicleDeliveries).toHaveBeenCalledExactlyOnceWith('900719925474099302',1,10)
})
it('a late response for the previous vehicle cannot replace the new vehicle records', async () => {
let resolveOld!: (value: Awaited>) => void
vi.mocked(api.listVehicleDeliveries).mockImplementationOnce(() => new Promise(resolve => { resolveOld=resolve }))
const wrapper = mount()
await wrapper.setProps({ vehicleId: '900719925474099302' }); await flushPromises()
resolveOld(result('DL-OLD') as Awaited>); await flushPromises()
expect(wrapper.findComponent({ name: 'DataTable' }).props('data')).toEqual(result('DL-1').records)
})
it('changes use the history endpoint and do not reveal current customer delivery data', async () => {
mount('changes'); await flushPromises()
expect(api.listVehicleAssignmentChanges).toHaveBeenCalledExactlyOnceWith('900719925474099301',1,10)
expect(api.listVehicleDeliveries).not.toHaveBeenCalled()
})
it('failed reads show an error and clear stale rows instead of showing unrelated prior data', async () => {
const wrapper = mount(); await flushPromises()
vi.mocked(api.listVehicleDeliveries).mockRejectedValueOnce(new Error('读取失败'))
await wrapper.find('button').trigger('click'); await flushPromises()
expect(wrapper.findComponent({ name: 'DataTable' }).props('data')).toEqual([])
expect(wrapper.findComponent({ name: 'LoadErrorState' }).exists()).toBe(true)
})