import { flushPromises, mount } from '@vue/test-utils' import { beforeEach, expect, it, vi } from 'vitest' import InboundOrdersView from './InboundOrdersView.vue' import { getFbaAppointment, listInboundOrders, updateFbaAppointment, type FbaAppointmentDto } from '../api/inboundOrders' vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => true }) })) vi.mock('vue-router', () => ({ useRouter: () => ({ push: vi.fn() }), onBeforeRouteLeave: vi.fn(), onBeforeRouteUpdate: vi.fn() })) vi.mock('element-plus', () => ({ ElMessage: { warning: vi.fn(), success: vi.fn() } })) vi.mock('../api/inboundOrders', async original => ({ ...await original(), listInboundOrders: vi.fn(), getFbaAppointment: vi.fn(), updateFbaAppointment: vi.fn() })) const appointment: FbaAppointmentDto = { id: '1', appointmentNo: 'YY-TEST', version: 2, originWarehouseId: 'warehouse-1', appointmentStatus: 'PENDING', selectedCount: 1, fbaWarehouseCode: 'ONT8', timezone: 'America/Los_Angeles', items: [{ id: 'item-1', customerId: 'customer-1', sourceKey: 'BOOKING:BK-TEST', orderId: '9007199254740993', inboundCode: 'IN-TEST', fbaWarehouseCode: 'ONT8', packageCount: 20 }] } function render() { return mount(InboundOrdersView, { global: { stubs: { AdminPage: { template: '
' }, ListPageLayout: { template: '
' }, DataTable: { props: ['data'], template: '
' }, AppDialog: { props: ['modelValue', 'showConfirm', 'confirmText'], template: '
' }, FbaAppointmentFields: { name: 'FbaAppointmentFields', props: ['model', 'sources', 'disabled'], template: '
' }, ElButton: { props: ['disabled'], template: '' }, SmartDispatchDialog: true, QueryToolbar: true, OperationErrorToast: true, LoadErrorState: true, ApiErrorMeta: true, } } }) } beforeEach(() => { vi.clearAllMocks() vi.mocked(listInboundOrders).mockResolvedValue({ records: [{ lineId: 'line-1', planId: 'plan-1', planNo: 'PLAN-TEST', customerId: 'customer-1', orderId: '9007199254740993', overseasWarehouseId: 'warehouse-1', fbaWarehouseCode: 'ONT8', packageCount: 20, status: 'COMPLETED', appointmentNo: appointment.appointmentNo, appointmentStatus: 'PENDING' }], total: 1, page: 1, size: 10 }) vi.mocked(getFbaAppointment).mockResolvedValue(appointment) vi.mocked(updateFbaAppointment).mockResolvedValue({ ...appointment, version: 3, appointmentStatus: 'SUCCESS' }) }) it('uses all canonical appointment items and blocks formal submission until cargo is verified', async () => { const wrapper = render(); await flushPromises() await wrapper.findAll('button').find(button => button.text() === '预约')!.trigger('click'); await flushPromises() const fields = wrapper.getComponent({ name: 'FbaAppointmentFields' }) expect(fields.props('sources')).toEqual([{ sourceKey: 'BOOKING:BK-TEST', customerId: 'customer-1', destinationKey: 'FBA:ONT8' }]) Object.assign(fields.props('model'), { appointmentStatus: 'SUCCESS', confirmationNo: 'EXT-TEST', appointmentAt: '2026-10-21T10:00:00' }) await wrapper.findAll('button').find(button => button.text() === '保存预约安排')!.trigger('click'); await flushPromises() expect(updateFbaAppointment).not.toHaveBeenCalled() fields.vm.$emit('confirmationReady', true); await flushPromises() await wrapper.findAll('button').find(button => button.text() === '保存预约安排')!.trigger('click'); await flushPromises() expect(updateFbaAppointment).toHaveBeenCalledWith('YY-TEST', expect.objectContaining({ version: 2, details: expect.objectContaining({ appointmentStatus: 'SUCCESS', confirmationNo: 'EXT-TEST' }) })) wrapper.unmount() }) it('keeps cargo supplementation disabled when viewing an appointment', async () => { const wrapper = render(); await flushPromises() await wrapper.findAll('button').find(button => button.text() === '查看预约')!.trigger('click'); await flushPromises() expect(wrapper.getComponent({ name: 'FbaAppointmentFields' }).props('disabled')).toBe(true) expect(wrapper.findAll('button').some(button => button.text() === '保存预约安排')).toBe(false) expect(updateFbaAppointment).not.toHaveBeenCalled(); wrapper.unmount() })