97 lines
5.5 KiB
TypeScript
97 lines
5.5 KiB
TypeScript
import { mount, flushPromises } from '@vue/test-utils'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import ElementPlus from 'element-plus'
|
|
import ContainerLastLegFeesPanel from './ContainerLastLegFeesPanel.vue'
|
|
|
|
const mocks = vi.hoisted(() => ({ upload: vi.fn(), metadata: vi.fn(), download: vi.fn(), create: vi.fn(), fees: vi.fn() }))
|
|
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => true }) }))
|
|
vi.mock('@/modules/finance', () => ({ getFinancePaymentVoucher: mocks.metadata, downloadFinancePaymentVoucher: mocks.download }))
|
|
vi.mock('@/modules/loading-lists', () => ({ uploadContainerFeePaymentVoucher: mocks.upload, listContainerFeeSupplierOptions: async () => [] }))
|
|
vi.mock('../api/overseasContainerFees', () => ({
|
|
listOverseasContainerFees: mocks.fees, listOverseasContainerCustomers: async () => [{ customerId: '11', customerName: '客户甲' }],
|
|
createOverseasContainerFee: mocks.create, adjustOverseasContainerFee: vi.fn(), reviewOverseasContainerFee: vi.fn(), submitOverseasContainerFee: vi.fn(), voidOverseasContainerFee: vi.fn(),
|
|
}))
|
|
|
|
async function setup(readonly = false) {
|
|
const wrapper = mount(ContainerLastLegFeesPanel, { props: { containerBookingId: '99', containerNo: 'CONT-99', readonly }, global: { plugins: [ElementPlus], stubs: {
|
|
AppDialog: { props: ['modelValue', 'title', 'confirmDisabled'], template: '<section v-if="modelValue"><h3>{{ title }}</h3><slot /><button :disabled="confirmDisabled" @click="$emit(\'confirm\')">保存</button></section>' },
|
|
} } })
|
|
await flushPromises()
|
|
return wrapper
|
|
}
|
|
type FormState = { form: { customerId: string; settlementMode: string }; dialogOpen: boolean }
|
|
async function upload(wrapper: Awaited<ReturnType<typeof setup>>, name: string) {
|
|
const input = wrapper.get('input[type="file"]')
|
|
Object.defineProperty(input.element, 'files', { configurable: true, value: [new File(['image'], name, { type: 'image/png' })] })
|
|
await input.trigger('change')
|
|
await flushPromises()
|
|
}
|
|
describe('尾程付款凭证', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
mocks.fees.mockResolvedValue([])
|
|
vi.stubGlobal('ResizeObserver', class { observe() {} unobserve() {} disconnect() {} })
|
|
URL.createObjectURL = vi.fn(() => 'blob:voucher')
|
|
URL.revokeObjectURL = vi.fn()
|
|
mocks.metadata.mockResolvedValue({ fileId: '91', fileName: '付款.png', contentType: 'image/png' })
|
|
mocks.download.mockResolvedValue(new Blob(['image']))
|
|
})
|
|
|
|
it('作废待财务确认时保留有效来源,停止调整和重复作废', async () => {
|
|
mocks.fees.mockResolvedValue([{ sourceFeeId: '81', customerId: '11', amount: 10, reviewStatus: 'APPROVED', sourceStatus: 'ACTIVE', voidStatus: 'PENDING_FINANCE', paymentVoucherFileIds: [] }])
|
|
const wrapper = await setup()
|
|
expect(wrapper.text()).toContain('待财务确认')
|
|
expect(wrapper.text()).not.toContain('已作废')
|
|
expect(wrapper.findAll('button').some(button => ['调整', '作废'].includes(button.text()))).toBe(false)
|
|
wrapper.unmount()
|
|
})
|
|
|
|
it('显示上传文件名,允许再次上传替换和移除', async () => {
|
|
const wrapper = await setup()
|
|
await wrapper.get('button').trigger('click')
|
|
const state = (wrapper.vm.$ as unknown as { setupState: FormState }).setupState
|
|
state.form.settlementMode = 'DIRECT_PAID'
|
|
await flushPromises()
|
|
mocks.upload.mockResolvedValueOnce({ fileId: '91', fileName: '付款.png' }).mockResolvedValueOnce({ fileId: '92', fileName: '新凭证.png' })
|
|
await upload(wrapper, '付款.png')
|
|
expect(mocks.upload).toHaveBeenCalledWith('11', expect.any(File))
|
|
expect(wrapper.text()).toContain('付款.png')
|
|
await upload(wrapper, '新凭证.png')
|
|
expect(wrapper.text()).toContain('新凭证.png')
|
|
expect(wrapper.text()).not.toContain('付款.png')
|
|
await wrapper.findAll('button').find(b => b.text() === '移除')!.trigger('click')
|
|
expect(wrapper.text()).not.toContain('新凭证.png')
|
|
wrapper.unmount()
|
|
})
|
|
|
|
it('上传中禁止保存,客户切换后忽略旧客户上传结果', async () => {
|
|
const wrapper = await setup()
|
|
await wrapper.get('button').trigger('click')
|
|
const state = (wrapper.vm.$ as unknown as { setupState: FormState }).setupState
|
|
state.form.settlementMode = 'DIRECT_PAID'
|
|
await flushPromises()
|
|
let complete!: (file: { fileId: string; fileName: string }) => void
|
|
mocks.upload.mockReturnValue(new Promise(resolve => { complete = resolve }))
|
|
await upload(wrapper, '旧客户.png')
|
|
expect(wrapper.findAll('button').find(b => b.text() === '保存')!.attributes('disabled')).toBeDefined()
|
|
state.form.customerId = '12'
|
|
complete({ fileId: '91', fileName: '旧客户.png' })
|
|
await flushPromises()
|
|
expect(wrapper.text()).not.toContain('旧客户.png')
|
|
wrapper.unmount()
|
|
})
|
|
|
|
it('只读列表能查看已保存的待审核凭证,并在关闭时释放预览资源', async () => {
|
|
mocks.fees.mockResolvedValue([{ sourceFeeId: '81', customerId: '11', amount: 10, reviewStatus: 'PENDING', paymentVoucherFileIds: ['91'] }])
|
|
const wrapper = await setup(true)
|
|
await wrapper.findAll('button').find(b => b.text() === '付款凭证 1')!.trigger('click')
|
|
await flushPromises()
|
|
expect(mocks.metadata).toHaveBeenCalledWith('11', '91')
|
|
expect(mocks.download).toHaveBeenCalledWith('11', '91')
|
|
expect(wrapper.get('img').attributes('src')).toBe('blob:voucher')
|
|
expect(wrapper.get('a[download]').attributes('download')).toBe('付款.png')
|
|
wrapper.unmount()
|
|
expect(URL.revokeObjectURL).toHaveBeenCalledWith('blob:voucher')
|
|
})
|
|
})
|