This commit is contained in:
2026-10-16 18:25:49 +08:00
parent 2705fdbc49
commit 4806f88d7c
6 changed files with 121 additions and 167 deletions
@@ -1,96 +1,87 @@
import { flushPromises, mount } from '@vue/test-utils'
import { defineComponent, h } from 'vue'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { ElMessage } from 'element-plus'
import WarehouseTransferReviewDialog from './WarehouseTransferReviewDialog.vue'
import { getWarehouseTransfer, reviewWarehouseTransfer } from '../api/warehouseTransfers'
vi.mock('../api/warehouseTransfers', async importOriginal => ({
...await importOriginal<typeof import('../api/warehouseTransfers')>(),
const reviewedTransfer = { id: '1', transferNo: 'WT-1', packageCount: 2, needRelabel: false, status: 'WAIT_PDA_RECEIVING', items: [], cartons: [], pallets: [], relabelBindings: [] }
vi.mock('../api/warehouseTransfers', () => ({
getWarehouseTransfer: vi.fn(),
reviewWarehouseTransfer: vi.fn(),
}))
vi.mock('element-plus', () => ({ ElMessage: { success: vi.fn(), error: vi.fn() } }))
const AppDialogStub = defineComponent({
name: 'AppDialog',
props: { modelValue: Boolean },
props: { modelValue: Boolean, confirmLoading: Boolean, title: String, confirmText: String, cancelText: String },
emits: ['confirm', 'update:modelValue'],
setup(props, { slots }) {
return () => props.modelValue ? h('section', { class: 'dialog' }, slots.default?.()) : null
setup(props, { slots, emit }) {
return () => props.modelValue ? h('section', [
h('h2', props.title), slots.default?.(),
h('button', { class: 'back', disabled: props.confirmLoading, onClick: () => emit('update:modelValue', false) }, props.cancelText),
h('button', { class: 'approve', disabled: props.confirmLoading, onClick: () => emit('confirm') }, props.confirmText),
]) : null
},
})
const DataTableStub = defineComponent({
name: 'DataTable',
props: { data: { type: Array, default: () => [] } },
setup(props) {
return () => h('div', { class: 'data-table' }, JSON.stringify(props.data))
},
})
function detail(transferNo: string) {
return {
id: `id-${transferNo}`,
transferNo,
packageCount: 2,
needRelabel: false,
status: 'PENDING_REVIEW',
items: [{ id: 'item-1', skuCode: 'SKU-1', productNameZh: '测试货物', packageCount: 2 }],
cartons: [],
pallets: [],
relabelBindings: [],
}
}
function mountDialog(props: { modelValue: boolean; customerId: string; customerName: string; transferNo: string }) {
function mountDialog() {
return mount(WarehouseTransferReviewDialog, {
props,
global: {
stubs: {
AppDialog: AppDialogStub,
DataTable: DataTableStub,
LoadErrorState: true,
ApiErrorMeta: true,
ElForm: { template: '<form><slot /></form>' },
ElFormItem: { template: '<label><slot /></label>' },
ElRadioGroup: { template: '<div><slot /></div>' },
ElRadioButton: { template: '<button type="button"><slot /></button>' },
ElInput: { template: '<textarea />' },
},
},
props: { modelValue: true, customerId: '20001', customerName: '测试客户', transferNo: 'WT-1' },
global: { stubs: { AppDialog: AppDialogStub } },
})
}
describe('WarehouseTransferReviewDialog', () => {
beforeEach(() => {
vi.mocked(getWarehouseTransfer).mockReset()
vi.mocked(reviewWarehouseTransfer).mockReset()
beforeEach(() => { vi.clearAllMocks() })
it('shows a concise confirmation without fetching detail tables or review inputs', () => {
const wrapper = mountDialog()
expect(wrapper.text()).toContain('仓储转运单审核')
expect(wrapper.text()).toContain('审核通过后,转运单将进入海外仓收货打托作业。')
expect(wrapper.find('.back').text()).toBe('返回')
expect(wrapper.find('.approve').text()).toBe('审核通过')
expect(wrapper.find('textarea, input, table').exists()).toBe(false)
expect(getWarehouseTransfer).not.toHaveBeenCalled()
})
it('loads and renders review details when first mounted already open', async () => {
vi.mocked(getWarehouseTransfer).mockResolvedValue(detail('WT-1'))
const wrapper = mountDialog({ modelValue: true, customerId: '20001', customerName: '测试客户', transferNo: 'WT-1' })
await flushPromises()
expect(getWarehouseTransfer).toHaveBeenCalledTimes(1)
expect(getWarehouseTransfer).toHaveBeenCalledWith('20001', 'WT-1')
expect(wrapper.text()).toContain('WT-1')
expect(wrapper.text()).toContain('测试货物')
wrapper.unmount()
it('return closes without approving or rejecting the order', async () => {
const wrapper = mountDialog()
await wrapper.find('.back').trigger('click')
expect(wrapper.emitted('update:modelValue')).toEqual([[false]])
expect(reviewWarehouseTransfer).not.toHaveBeenCalled()
expect(wrapper.emitted('reviewed')).toBeUndefined()
})
it('reloads details when an open dialog switches to another transfer', async () => {
vi.mocked(getWarehouseTransfer)
.mockResolvedValueOnce(detail('WT-1'))
.mockResolvedValueOnce(detail('WT-2'))
const wrapper = mountDialog({ modelValue: true, customerId: '20001', customerName: '测试客户', transferNo: 'WT-1' })
it('approves in the selected customer scope once and refreshes only after success', async () => {
let finish!: () => void
vi.mocked(reviewWarehouseTransfer).mockReturnValue(new Promise(resolve => { finish = () => resolve(reviewedTransfer) }))
const wrapper = mountDialog()
const dialog = wrapper.findComponent(AppDialogStub)
dialog.vm.$emit('confirm')
dialog.vm.$emit('confirm')
await flushPromises()
await wrapper.setProps({ customerId: '20002', transferNo: 'WT-2' })
expect(reviewWarehouseTransfer).toHaveBeenCalledExactlyOnceWith('20001', 'WT-1', 'APPROVE')
expect(dialog.props('confirmLoading')).toBe(true)
expect(wrapper.emitted('reviewed')).toBeUndefined()
finish()
await flushPromises()
expect(wrapper.emitted('reviewed')).toHaveLength(1)
expect(wrapper.emitted('update:modelValue')).toEqual([[false]])
expect(dialog.props('confirmLoading')).toBe(false)
})
expect(getWarehouseTransfer).toHaveBeenLastCalledWith('20002', 'WT-2')
expect(wrapper.text()).toContain('WT-2')
wrapper.unmount()
it('keeps the dialog open and allows retry after an approval failure', async () => {
vi.mocked(reviewWarehouseTransfer).mockRejectedValueOnce(new Error('审核失败')).mockResolvedValueOnce(reviewedTransfer)
const wrapper = mountDialog()
await wrapper.find('.approve').trigger('click')
await flushPromises()
expect(ElMessage.error).toHaveBeenCalled()
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
expect(wrapper.emitted('reviewed')).toBeUndefined()
expect(wrapper.findComponent(AppDialogStub).props('confirmLoading')).toBe(false)
await wrapper.find('.approve').trigger('click')
await flushPromises()
expect(wrapper.emitted('reviewed')).toHaveLength(1)
})
})