51 lines
5.6 KiB
TypeScript
51 lines
5.6 KiB
TypeScript
import { flushPromises, mount } from '@vue/test-utils'
|
|
import { beforeEach, expect, it, vi } from 'vitest'
|
|
import WorkReceiptPlans from './WorkReceiptPlans.vue'
|
|
import { getContainerPlanProgress, getContainerInboundPlanPreview, convertLastMileContainerToInboundPlans, type ContainerInboundPlanPreviewDto } from '@/modules/overseas-warehouse'
|
|
import type { LeaveGuard } from './useWorkDraft'
|
|
const state = vi.hoisted(() => ({ canRead: true }))
|
|
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => state.canRead }) }))
|
|
vi.mock('element-plus', () => ({ ElMessage: { warning: vi.fn(), success: vi.fn() }, ElMessageBox: { confirm: vi.fn() } }))
|
|
vi.mock('@/modules/overseas-warehouse', async original => ({ ...await original<typeof import('@/modules/overseas-warehouse')>(), getContainerPlanProgress: vi.fn(), getContainerInboundPlanPreview: vi.fn(), convertLastMileContainerToInboundPlans: vi.fn() }))
|
|
let guard: LeaveGuard
|
|
function render() { return mount(WorkReceiptPlans, { props: { containerBookingId: '9007199254740993', canWrite: true }, global: { provide: { 'appointment-work-leave-guard': (value: LeaveGuard) => { guard = value; return () => undefined } }, stubs: { ElButton: { props: ['disabled'], template: '<button :disabled="disabled"><slot /></button>' }, LoadErrorState: true, ApiErrorMeta: true } } }) }
|
|
function button(wrapper: ReturnType<typeof render>, text: string) { return wrapper.findAll('button').find(button => button.text() === text)! }
|
|
function preview(overrides: Partial<ContainerInboundPlanPreviewDto> = {}) { return { sourceContainerBookingId: '9007199254740993', containerNo: 'TEST-CN', overseasWarehouseName: '接仓仓库', snapshotVersion: 4, snapshotHash: 'snapshot-4', pendingOrderCount: 1, blockedOrderCount: 0, sourcePalletCount: 2, supplementPalletCount: 1, totalPlannedPalletCount: 0, ready: true, groups: [], ...overrides } as ContainerInboundPlanPreviewDto }
|
|
beforeEach(() => { vi.clearAllMocks(); state.canRead = true; vi.mocked(getContainerPlanProgress).mockResolvedValue({ summary: { containerNo: 'TEST-CN', overseasWarehouseName: '接仓仓库' }, orders: [{ orderId: 'internal-1', customerId: '9007199254740999', planId: 'internal-plan', planNo: 'IP-001', planValid: true, inboundCode: 'IN-001' }, { orderId: 'internal-2', customerId: 'customer-b', planId: null, planNo: null, planValid: false, inboundCode: 'IN-002' }] } as never) })
|
|
it('opens a real plan in the exact customer scope while leaving missing plans unavailable', async () => {
|
|
const wrapper = render(); await flushPromises()
|
|
expect(getContainerPlanProgress).toHaveBeenCalledExactlyOnceWith('9007199254740993')
|
|
const plans = wrapper.findAll('button').filter(item => item.text() === '查看原接仓记录')
|
|
await plans[0]!.trigger('click')
|
|
expect(wrapper.emitted('external')).toEqual([['/overseas-warehouse/inbound-orders/IP-001?customerId=9007199254740999']])
|
|
expect(plans[1]!.attributes('disabled')).toBeDefined()
|
|
expect(wrapper.text()).not.toContain('internal-plan'); expect(wrapper.text()).not.toContain('9007199254740999'); wrapper.unmount()
|
|
})
|
|
it('does not read the container source without its original permission', async () => {
|
|
state.canRead = false; const wrapper = render(); await flushPromises(); expect(getContainerPlanProgress).not.toHaveBeenCalled(); wrapper.unmount()
|
|
})
|
|
it('submits the actual preview snapshot and replays the same request after an unknown result', async () => {
|
|
vi.mocked(getContainerInboundPlanPreview).mockResolvedValue(preview())
|
|
vi.mocked(convertLastMileContainerToInboundPlans).mockRejectedValueOnce(new Error('lost response')).mockResolvedValueOnce([])
|
|
const wrapper = render(); await flushPromises(); await button(wrapper, '核对本柜入库计划预览').trigger('click'); await flushPromises()
|
|
await button(wrapper, '确认生成本柜计划').trigger('click'); await flushPromises()
|
|
const original = vi.mocked(convertLastMileContainerToInboundPlans).mock.calls[0]!
|
|
expect(original).toEqual([{ sourceContainerBookingId: '9007199254740993', snapshotVersion: 4, snapshotHash: 'snapshot-4' }, expect.any(String)])
|
|
expect(await guard()).toBe(false)
|
|
await button(wrapper, '重试本次计划生成').trigger('click'); await flushPromises()
|
|
expect(vi.mocked(convertLastMileContainerToInboundPlans).mock.calls[1]).toEqual(original)
|
|
expect(wrapper.emitted('updated')).toHaveLength(1); wrapper.unmount()
|
|
})
|
|
it('uses the original resource recovery snapshot and key instead of creating new plans', async () => {
|
|
vi.mocked(getContainerInboundPlanPreview).mockResolvedValue(preview({ pendingOrderCount: 0, resourceRetry: { idempotencyKey: 'original-key', snapshotVersion: 2, snapshotHash: 'original-snapshot' } }))
|
|
vi.mocked(convertLastMileContainerToInboundPlans).mockResolvedValue([])
|
|
const wrapper = render(); await flushPromises(); await button(wrapper, '核对本柜入库计划预览').trigger('click'); await flushPromises()
|
|
await button(wrapper, '重试原资源确认').trigger('click'); await flushPromises()
|
|
expect(convertLastMileContainerToInboundPlans).toHaveBeenCalledWith({ sourceContainerBookingId: '9007199254740993', snapshotVersion: 2, snapshotHash: 'original-snapshot' }, 'original-key'); wrapper.unmount()
|
|
})
|
|
it('does not submit a blocked preview', async () => {
|
|
vi.mocked(getContainerInboundPlanPreview).mockResolvedValue(preview({ ready: false, blockedOrderCount: 1 }))
|
|
const wrapper = render(); await flushPromises(); await button(wrapper, '核对本柜入库计划预览').trigger('click'); await flushPromises()
|
|
expect(button(wrapper, '确认生成本柜计划').attributes('disabled')).toBeDefined(); expect(convertLastMileContainerToInboundPlans).not.toHaveBeenCalled(); wrapper.unmount()
|
|
})
|