import { afterEach, expect, it, vi } from 'vitest' import { flushPromises, shallowMount, type VueWrapper } from '@vue/test-utils' import VehiclesView from './VehiclesView.vue' import * as api from '../api/overseasMasterData' vi.mock('vue-router', () => ({ useRouter: () => ({ push: vi.fn() }) })) vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => true }) })) vi.mock('../api/overseasMasterData', () => ({ listVehicles: vi.fn(), getVehicle: vi.fn(), createVehicle: vi.fn(), updateVehicle: vi.fn(), changeVehicleStatus: vi.fn(), exportVehicles: vi.fn() })) const layout = { template: '
' } const table = { name: 'DataTable', props: ['data', 'total', 'loading'], template: '

{{ row.plateNumber }}

' } type Page = Awaited> function deferred() { let resolve!: (page: Page) => void, reject!: (reason: Error) => void const promise = new Promise((yes, no) => { resolve = yes; reject = no }) return { promise, resolve, reject } } function page(plateNumber: string): Page { return { records: [{ id: plateNumber, plateNumber } as Page['records'][number]], total: 1, page: 1, size: 20, pages: 1 } } const wrappers: VueWrapper[] = [] function mount() { const wrapper = shallowMount(VehiclesView, { global: { stubs: { AdminPage: layout, ListPageLayout: layout, DataTable: table, QueryToolbar: true, LoadErrorState: true, AppDialog: true } } }) wrappers.push(wrapper); return wrapper } afterEach(() => { wrappers.splice(0).forEach(wrapper => wrapper.unmount()); vi.clearAllMocks() }) it.each(['success', 'failure'] as const)('keeps the selected ownership results after a stale %s', async outcome => { const old = deferred(), current = deferred() vi.mocked(api.listVehicles).mockReturnValueOnce(old.promise).mockReturnValueOnce(current.promise) const wrapper = mount() expect(wrapper.get('header .workbench-list-tabs').attributes('aria-label')).toBe('车辆归属') await wrapper.get('[role="tab"][aria-selected="false"]').trigger('click') expect(api.listVehicles).toHaveBeenLastCalledWith(expect.objectContaining({ ownership: 'DISPATCHED' })) current.resolve(page('EXTERNAL-CURRENT')); await flushPromises() if (outcome === 'success') old.resolve(page('OWNED-STALE')) else old.reject(new Error('old request failed')) await flushPromises() expect(wrapper.text()).toContain('EXTERNAL-CURRENT') expect(wrapper.text()).not.toContain('OWNED-STALE') expect(wrapper.findComponent({ name: 'LoadErrorState' }).exists()).toBe(false) expect(wrapper.findComponent({ name: 'DataTable' }).props('total')).toBe(1) }) it('keeps loading until the currently selected query finishes', async () => { const old = deferred(), current = deferred() vi.mocked(api.listVehicles).mockReturnValueOnce(old.promise).mockReturnValueOnce(current.promise) const wrapper = mount() await wrapper.get('[role="tab"][aria-selected="false"]').trigger('click') old.resolve(page('OWNED-STALE')); await flushPromises() expect(wrapper.findComponent({ name: 'DataTable' }).props('loading')).toBe(true) expect(wrapper.text()).not.toContain('OWNED-STALE') current.resolve(page('EXTERNAL-CURRENT')); await flushPromises() expect(wrapper.findComponent({ name: 'DataTable' }).props('loading')).toBe(false) expect(api.listVehicles).toHaveBeenCalledTimes(2) }) it('opens a new vehicle with unknown fuel consumption blank instead of clamping it to 0.01', async () => { vi.mocked(api.listVehicles).mockResolvedValue({ records: [], total: 0, page: 1, size: 20, pages: 0 }) const wrapper = shallowMount(VehiclesView, { global: { stubs: { AdminPage: layout, ListPageLayout: layout, QueryToolbar: true, LoadErrorState: true, DataTable: { ...table, template: '
' }, AppDialog: { name: 'AppDialog', props: ['modelValue'], emits: ['confirm'], template: '
' }, ElButton: { template: '' }, ElForm: layout, ElFormItem: layout, ElInputNumber: { name: 'ElInputNumber', props: ['modelValue'], template: '' }, ElInput: true, ElSelect: true, ElOption: true, ElTag: true, } } }) wrappers.push(wrapper); await flushPromises() await wrapper.findAll('button').find(button => button.text() === '添加车辆')!.trigger('click') await flushPromises() expect(wrapper.findAllComponents({ name: 'ElInputNumber' })[0]!.get('input').element.value).toBe('') await wrapper.findAll('button').find(button => button.text() === '保存')!.trigger('click') await flushPromises() expect(api.createVehicle).not.toHaveBeenCalled() })