Files
admin-web/src/modules/overseas-master-data/components/FleetQuoteImport.test.ts
T

59 lines
4.6 KiB
TypeScript

import { afterEach, beforeEach, expect, it, vi } from 'vitest'
import { shallowMount, flushPromises, type VueWrapper } from '@vue/test-utils'
import FleetQuoteImport from './FleetQuoteImport.vue'
import { ApiResponseError } from '@/shared/api/http'
import { fleetQuoteCsvHeader } from '../fleetQuoteCsv'
import * as api from '../api/fleetQuotes'
vi.mock('../api/fleetQuotes', async original => ({ ...(await original<typeof import('../api/fleetQuotes')>()), importFleetQuotes: vi.fn() }))
const wrappers: VueWrapper[] = []
async function mount() {
const wrapper = shallowMount(FleetQuoteImport, { props: { modelValue: true, kind: 'SALE' }, global: { stubs: {
AppDialog: { template: '<div><slot/><slot name="footer"/></div>' },
FleetQuotePartySelect: { name: 'FleetQuotePartySelect', props: ['modelValue', 'kind', 'disabled'], emits: ['update:modelValue'], template: '<div/>' },
ElButton: { props: ['disabled', 'loading'], template: '<button :disabled="disabled || loading"><slot/></button>' },
ElAlert: { props: ['title'], template: '<p>{{ title }}<slot/></p>' }, ApiErrorMeta: true,
} } }); wrappers.push(wrapper)
wrapper.findComponent({ name: 'FleetQuotePartySelect' }).vm.$emit('update:modelValue', '101'); await flushPromises(); return wrapper
}
async function pick(wrapper: VueWrapper, city = 'QA-FIRST', size = 100, text?: () => Promise<string>) {
Object.defineProperty(wrapper.find('input[type="file"]').element, 'files', { configurable: true, value: [{ size, text: text || (async () => `${fleetQuoteCsvHeader.join(',')}\n${city},QA-DEST,10,USD,,0,12,2026-01-01,2100-01-01,`) }] })
await wrapper.find('input[type="file"]').trigger('change'); await flushPromises()
}
async function save(wrapper: VueWrapper) { await wrapper.findAll('button').find(b => ['确认导入', '按原请求重试'].includes(b.text()))!.trigger('click'); await flushPromises() }
beforeEach(() => vi.clearAllMocks()); afterEach(() => wrappers.splice(0).forEach(w => w.unmount()))
it('definite import rejection unlocks file selection and corrected rows use a new key', async () => {
const wrapper = await mount(); await pick(wrapper)
vi.mocked(api.importFleetQuotes).mockRejectedValueOnce(new ApiResponseError('组合重复', 'A0409', 200)); await save(wrapper)
const first = vi.mocked(api.importFleetQuotes).mock.calls[0]!
expect(wrapper.find('input[type="file"]').attributes('disabled')).toBeUndefined()
await pick(wrapper, 'QA-CORRECTED'); vi.mocked(api.importFleetQuotes).mockResolvedValue({ importedRows: 1 }); await save(wrapper)
const second = vi.mocked(api.importFleetQuotes).mock.calls[1]!
expect(second[0]).not.toBe(first[0]); expect(second[1][0]?.originCity).toBe('QA-CORRECTED')
})
it('unknown result preserves original purpose, key and rows across closing and category changes', async () => {
const wrapper = await mount(); await pick(wrapper)
vi.mocked(api.importFleetQuotes).mockRejectedValueOnce(new Error('network')); await save(wrapper)
const call = vi.mocked(api.importFleetQuotes).mock.calls[0]!
const first = [call[0], call[1].map(row => ({ ...row }))]
await wrapper.setProps({ modelValue: false, kind: 'PURCHASE' }); await wrapper.setProps({ modelValue: true }); await flushPromises()
expect(wrapper.findComponent({ name: 'FleetQuotePartySelect' }).props('kind')).toBe('SALE')
expect(wrapper.find('input[type="file"]').attributes('disabled')).toBeDefined()
vi.mocked(api.importFleetQuotes).mockResolvedValue({ importedRows: 1 }); await save(wrapper)
expect(vi.mocked(api.importFleetQuotes).mock.calls[1]).toEqual(first)
})
it('selecting an oversized replacement file cannot accidentally submit the previous valid file', async () => {
const wrapper = await mount(); await pick(wrapper); await pick(wrapper, 'TOO-LARGE', 500001)
expect(wrapper.findAll('button').find(b => b.text() === '确认导入')!.attributes('disabled')).toBeDefined()
expect(wrapper.text()).not.toContain('QA-FIRST'); expect(api.importFleetQuotes).not.toHaveBeenCalled()
})
it('a late old file read cannot replace the most recently selected CSV', async () => {
const wrapper = await mount(); let release!: (value: string) => void
const slow = new Promise<string>(resolve => { release = resolve })
await pick(wrapper, 'SLOW', 100, () => slow)
await pick(wrapper, 'QA-LATEST')
release(`${fleetQuoteCsvHeader.join(',')}\nQA-OLD,QA-DEST,10,USD,,0,12,2026-01-01,2100-01-01,`); await flushPromises()
expect(wrapper.text()).toContain('QA-LATEST'); expect(wrapper.text()).not.toContain('QA-OLD')
vi.mocked(api.importFleetQuotes).mockResolvedValue({ importedRows: 1 }); await save(wrapper)
expect(vi.mocked(api.importFleetQuotes).mock.calls[0]?.[1][0]?.originCity).toBe('QA-LATEST')
})