import { afterEach, beforeEach, expect, it, vi } from 'vitest' import { shallowMount, flushPromises, type VueWrapper } from '@vue/test-utils' import FleetQuoteEditor from './FleetQuoteEditor.vue' import { ApiResponseError } from '@/shared/api/http' import * as api from '../api/fleetQuotes' vi.mock('../api/fleetQuotes', async original => ({ ...(await original()), createFleetQuote: vi.fn(), updateFleetQuote: vi.fn() })) const wrappers: VueWrapper[] = [] const input = (name: string) => ({ name, props: ['modelValue'], emits: ['update:modelValue'], template: '' }) const slot = { template: '
' } async function mount() { const wrapper = shallowMount(FleetQuoteEditor, { props: { modelValue: false, quote: null, kind: 'SALE' }, global: { stubs: { AppDialog: { props: ['modelValue'], template: '
' }, ElForm: { name: 'ElForm', props: ['disabled'], template: '
' }, ElFormItem: slot, ElInput: input('ElInput'), ElInputNumber: input('ElInputNumber'), ElDatePicker: input('ElDatePicker'), ElSelect: slot, ElOption: true, FleetQuotePartySelect: input('FleetQuotePartySelect'), ElButton: { template: '' }, ElAlert: { props: ['title'], template: '

{{ title }}

' }, ApiErrorMeta: true, } } }); wrappers.push(wrapper); await wrapper.setProps({ modelValue: true }); await flushPromises() wrapper.findComponent({ name: 'FleetQuotePartySelect' }).vm.$emit('update:modelValue', '101') wrapper.findAllComponents({ name: 'ElInput' }).find(input => input.attributes('placeholder') === '请输入发货城市')!.vm.$emit('update:modelValue', 'QA-Origin') wrapper.findAllComponents({ name: 'ElInput' }).find(input => input.attributes('placeholder') === '请输入目的仓码,如 ONT8')!.vm.$emit('update:modelValue', 'QA-DEST') wrapper.findAllComponents({ name: 'ElInputNumber' })[0]!.vm.$emit('update:modelValue', 10) wrapper.findAllComponents({ name: 'ElInputNumber' })[2]!.vm.$emit('update:modelValue', 0) wrapper.findAllComponents({ name: 'ElDatePicker' })[1]!.vm.$emit('update:modelValue', '2100-01-01') await flushPromises(); return wrapper } async function clickSave(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('HTTP 200/A0409 unlocks the form so corrected content receives a new key', async () => { const wrapper = await mount(); vi.mocked(api.createFleetQuote).mockRejectedValueOnce(new ApiResponseError('报价组合重复', 'A0409', 200)) await clickSave(wrapper); const original = vi.mocked(api.createFleetQuote).mock.calls[0]! expect(wrapper.findComponent({ name: 'ElForm' }).props('disabled')).toBe(false); expect(wrapper.text()).not.toContain('按原请求重试') wrapper.findAllComponents({ name: 'ElInput' }).find(input => input.attributes('placeholder') === '请输入发货城市')!.vm.$emit('update:modelValue', 'QA-Another-Origin') vi.mocked(api.createFleetQuote).mockResolvedValue({ quoteNo: 'FQ-NEW', details: original[1], recordVersion: '0', partyName: '测试客户', status: 'ACTIVE', updatedAt: '' }) await clickSave(wrapper) const corrected = vi.mocked(api.createFleetQuote).mock.calls[1]! expect(corrected[0]).not.toBe(original[0]); expect(corrected[1].originCity).toBe('QA-Another-Origin'); expect(corrected[1].fullDeliveryPrice).toBe(0) }) it('unknown creation unlocks the current form and sends edited values with a fresh key', async () => { const wrapper = await mount(); vi.mocked(api.createFleetQuote).mockRejectedValueOnce(new Error('Network unavailable')) await clickSave(wrapper); const original = vi.mocked(api.createFleetQuote).mock.calls[0]! expect(wrapper.findComponent({ name: 'ElForm' }).props('disabled')).toBe(false) wrapper.findAllComponents({ name: 'ElInput' }).find(input => input.attributes('placeholder') === '请输入发货城市')!.vm.$emit('update:modelValue', 'CHANGED') await clickSave(wrapper) const next = vi.mocked(api.createFleetQuote).mock.calls[1]! expect(next[0]).not.toBe(original[0]); expect(next[1].originCity).toBe('CHANGED') })