import ElementPlus from 'element-plus' import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { reactive, ref } from 'vue' import { ApiResponseError } from '@/shared/api/http' import BusinessDocumentFees from '../components/BusinessDocumentFees.vue' import { getLocalLooseboardOrder } from '../api/platformOverseasBusiness' import type { LocalLooseboardDetail } from '../types' import LooseboardOrderDetailView from './LooseboardOrderDetailView.vue' const routing = vi.hoisted(() => ({ push: vi.fn(), route: { params: { orderId: 'LB-TEST' }, query: { customerId: '9007199254741999' } as Record } })) vi.mock('vue-router', () => ({ useRoute: () => routing.route, useRouter: () => ({ push: routing.push }) })) vi.mock('../api/platformOverseasBusiness', () => ({ getLocalLooseboardOrder: vi.fn() })) function order(overrides: Partial = {}): LocalLooseboardDetail { return { id: '9007199254741001', orderNo: 'LB-TEST', customerId: '9007199254741999', fleetArrangement: null, palletRequired: 'YES', transportType: 'WAREHOUSE_TO_WAREHOUSE', productName: '测试货物', estimatedPalletCount: 2, origin: 'LA', originAddress: '起运仓地址', destination: 'ONT', destinationAddress: '目的仓地址', originContactName: '发货人', originContactPhone: '10001', destinationContactName: '收货人', destinationContactPhone: '10002', pickupAt: '2026-10-20T09:30:00', deliveryAt: '2026-10-20T15:45:00', packageCount: 20, totalWeightKg: '100', totalVolumeCbm: '2', budgetAmount: '500', currency: 'USD', status: 'PENDING_ACCEPTANCE', version: 1, remark: '运输备注', createdBy: '7', createdAt: '2026-10-20T08:00:00', updatedAt: '2026-10-20T08:00:00', histories: [], ...overrides, } } function mountDetail() { return mount(LooseboardOrderDetailView, { global: { plugins: [ElementPlus], stubs: { BusinessDocumentFees: true, FleetArrangementSummary: true, DataTable: true } } }) } enableAutoUnmount(afterEach) beforeEach(() => { vi.clearAllMocks() routing.route = reactive({ params: { orderId: 'LB-TEST' }, query: { customerId: '9007199254741999' } }) vi.mocked(getLocalLooseboardOrder).mockResolvedValue(order()) }) describe('looseboard document fees', () => { it('refreshes the current status when returning to a cached document tab', async () => { const visible = ref(true) vi.mocked(getLocalLooseboardOrder).mockResolvedValueOnce(order({ status: 'WAITING_INBOUND' })) .mockResolvedValueOnce(order({ status: 'PENDING_DISPATCH' })) const wrapper = mount({ components: { LooseboardOrderDetailView }, setup: () => ({ visible }), template: '', }, { global: { plugins: [ElementPlus], stubs: { BusinessDocumentFees: true, FleetArrangementSummary: true, DataTable: true } } }) await flushPromises() expect(getLocalLooseboardOrder).toHaveBeenCalledTimes(1) expect(wrapper.find('.status-badge').text()).toBe('待入仓') visible.value = false; await flushPromises() visible.value = true; await flushPromises() expect(getLocalLooseboardOrder).toHaveBeenCalledTimes(2) expect(wrapper.find('.status-badge').text()).toBe('待派车') }) it('loads the customer scoped document and passes its exact identity to fees', async () => { const wrapper = mountDetail(); await flushPromises() expect(getLocalLooseboardOrder).toHaveBeenCalledWith('LB-TEST', '9007199254741999') expect(wrapper.findComponent(BusinessDocumentFees).props()).toMatchObject({ businessType: 'LOCAL_LOOSEBOARD', businessNo: 'LB-TEST', customerId: '9007199254741999', businessId: '9007199254741001', }) expect(wrapper.text()).toContain('起运仓地址') expect(wrapper.findAll('.status-badge')).toHaveLength(1) }) it('does not expose fees or query a document without a real customer', async () => { routing.route.query = {} const wrapper = mountDetail(); await flushPromises() expect(getLocalLooseboardOrder).not.toHaveBeenCalled() expect(wrapper.findComponent(BusinessDocumentFees).exists()).toBe(false) expect(wrapper.text()).toContain('缺少有效客户或订单信息') }) it('keeps error metadata and retries before exposing fee operations', async () => { vi.mocked(getLocalLooseboardOrder).mockRejectedValueOnce(new ApiResponseError('读取失败', 'A0409', 409, undefined, 'LB-409')).mockResolvedValueOnce(order()) const wrapper = mountDetail(); await flushPromises() expect(wrapper.text()).toContain('LB-409') expect(wrapper.findComponent(BusinessDocumentFees).exists()).toBe(false) wrapper.findComponent({ name: 'LoadErrorState' }).vm.$emit('retry'); await flushPromises() expect(wrapper.findComponent(BusinessDocumentFees).exists()).toBe(true) }) it('discards an older response when navigating to another order', async () => { let completeFirst!: (value: LocalLooseboardDetail) => void vi.mocked(getLocalLooseboardOrder).mockImplementationOnce(() => new Promise(resolve => { completeFirst = resolve })) .mockResolvedValueOnce(order({ id: '9007199254741002', orderNo: 'LB-NEXT' })) const wrapper = mountDetail() routing.route.params.orderId = 'LB-NEXT'; await flushPromises() completeFirst(order()); await flushPromises() expect(wrapper.findComponent(BusinessDocumentFees).props('businessId')).toBe('9007199254741002') expect(wrapper.findComponent(BusinessDocumentFees).props('businessNo')).toBe('LB-NEXT') }) })