Files
admin-web/src/modules/overseas-warehouse/pages/PalletsView.test.ts
T
2026-09-15 14:18:23 +08:00

125 lines
7.9 KiB
TypeScript

import ElementPlus from 'element-plus'
import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils'
import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { listAllPlatformWarehouses } from '@/modules/warehouses'
import AppDialog from '@/shared/components/AppDialog.vue'
import QueryToolbar from '@/shared/components/QueryToolbar.vue'
import { createPallet, getPallet, getPalletLabelPdf, getPalletSummary, listPallets, listReceivingOverseasWarehouses, updatePallet } from '../api/pallets'
import PalletsView from './PalletsView.vue'
vi.mock('vue-router', () => ({ useRouter: () => ({ push: vi.fn() }) }))
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => true }) }))
vi.mock('@/modules/warehouses', () => ({ listAllPlatformWarehouses: vi.fn() }))
vi.mock('../api/pallets', () => ({ createPallet: vi.fn(), getPallet: vi.fn(), getPalletLabelPdf: vi.fn(), getPalletSummary: vi.fn(), listPallets: vi.fn(), listReceivingOverseasWarehouses: vi.fn(), updatePallet: vi.fn() }))
class ResizeObserverStub implements ResizeObserver { observe() {} unobserve() {} disconnect() {} }
function memoryStorage(): Storage { const values = new Map<string, string>(); return { get length() { return values.size }, clear: () => values.clear(), getItem: (key) => values.get(key) ?? null, key: (index) => [...values.keys()][index] ?? null, removeItem: (key) => values.delete(key), setItem: (key, value) => values.set(key, value) } }
enableAutoUnmount(afterEach)
afterAll(() => vi.unstubAllGlobals())
describe('PalletsView', () => {
beforeEach(() => {
vi.stubGlobal('ResizeObserver', ResizeObserverStub)
vi.stubGlobal('localStorage', memoryStorage())
vi.mocked(listReceivingOverseasWarehouses).mockReset().mockResolvedValue({ records: [{ id: '200', customerId: '0', warehouseCode: 'LAX', warehouseName: '洛杉矶仓', warehouseType: 'OVERSEAS', status: 'ACTIVE' }], page: 1, size: 200, total: 1, pages: 1 })
vi.mocked(listAllPlatformWarehouses).mockReset().mockResolvedValue([{ id: '300', warehouseCode: 'ABE3', warehouseName: 'ABE3', warehouseType: 'FBA', status: 'ACTIVE' } as never])
const pallet = { id: '9007199254740993', customerId: '0', warehouseId: '200', locationId: null, palletCode: 'PLT-1', palletType: 'WOOD', fbaWarehouseCode: 'ABE3', capacityCbm: 2, unitPrice: 10, status: 'IDLE', remark: null, version: 7 }
vi.mocked(listPallets).mockReset().mockResolvedValue({ records: [pallet], page: 1, size: 10, total: 1, pages: 1 })
vi.mocked(getPalletSummary).mockReset().mockResolvedValue({ totalCount: 1, idleCount: 1, occupiedCount: 0, scrappedCount: 0 })
vi.mocked(getPallet).mockReset().mockResolvedValue(pallet)
vi.mocked(createPallet).mockReset()
vi.mocked(getPalletLabelPdf).mockReset()
vi.mocked(updatePallet).mockReset().mockResolvedValue(null)
})
it('loads the all-warehouse pallet list and summary when the page opens', async () => {
vi.mocked(getPalletSummary).mockResolvedValueOnce({ totalCount: 250, idleCount: 100, occupiedCount: 98, scrappedCount: 52 })
const wrapper = mount(PalletsView, { attachTo: document.body, global: { plugins: [ElementPlus] } })
await flushPromises()
expect(listPallets).toHaveBeenCalledWith('', { page: 1, size: 10, keyword: undefined, palletType: undefined, status: undefined })
expect(getPalletSummary).toHaveBeenCalledWith('', { page: 1, size: 10, keyword: undefined, palletType: undefined, status: undefined })
expect(wrapper.get('[aria-label="托盘管理列表"]').text()).toContain('PLT-1')
expect(wrapper.get('[aria-label="托盘管理列表"]').text()).not.toContain('请先选择仓库后查询')
expect(wrapper.get('[aria-label="海外托盘数量概览"]').text()).toContain('托盘总数250')
expect(wrapper.get('[aria-label="海外托盘数量概览"]').text()).toContain('闲置托盘100')
expect(wrapper.get('[aria-label="海外托盘数量概览"]').text()).toContain('占用托盘98')
expect(wrapper.get('[aria-label="海外托盘数量概览"]').text()).toContain('已报废52')
})
it('prints one pallet from the all-warehouse list and allows retry after failure', async () => {
const pdf = new Blob(['%PDF-label'], { type: 'application/pdf' })
vi.mocked(getPalletLabelPdf).mockRejectedValueOnce(new Error('打印服务暂不可用')).mockResolvedValueOnce(pdf)
const createUrl = vi.fn(() => 'blob:pallet-label')
vi.stubGlobal('URL', Object.assign(URL, { createObjectURL: createUrl, revokeObjectURL: vi.fn() }))
const downloads: string[] = []
const click = vi.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(function (this: HTMLAnchorElement) { downloads.push(this.download) })
try {
const wrapper = mount(PalletsView, { attachTo: document.body, global: { plugins: [ElementPlus] } })
await flushPromises()
const button = wrapper.findAll('button').filter((item) => item.text() === '打印').at(-1)!
await button.trigger('click')
await flushPromises()
expect(createUrl).not.toHaveBeenCalled()
expect(button.attributes('disabled')).toBeUndefined()
await button.trigger('click')
await flushPromises()
expect(getPalletLabelPdf).toHaveBeenNthCalledWith(2, '200', '9007199254740993')
expect(createUrl).toHaveBeenCalledWith(pdf)
expect(downloads).toEqual(['PLT-1-托盘码.pdf'])
expect(createPallet).not.toHaveBeenCalled()
expect(updatePallet).not.toHaveBeenCalled()
} finally { click.mockRestore() }
})
it('reloads all warehouses when the filters are reset', async () => {
const wrapper = mount(PalletsView, { attachTo: document.body, global: { plugins: [ElementPlus] } })
await flushPromises()
vi.mocked(listPallets).mockClear()
wrapper.findComponent(QueryToolbar).vm.$emit('reset', { warehouseId: '', code: '', type: '', status: '' })
await flushPromises()
expect(listPallets).toHaveBeenCalledWith('', { page: 1, size: 10, keyword: undefined, palletType: undefined, status: undefined })
})
it('loads the current detail version and keeps the edit open on a conflict', async () => {
vi.mocked(updatePallet).mockRejectedValueOnce(Object.assign(new Error('version conflict'), { code: 'A0409' }))
const wrapper = mount(PalletsView, { attachTo: document.body, global: { plugins: [ElementPlus] } })
await flushPromises()
wrapper.findComponent(QueryToolbar).vm.$emit('search', { warehouseId: '200', code: '', type: '', status: '' })
await flushPromises()
await wrapper.findAll('button.el-button--small').filter((button) => button.text().includes('编辑')).at(-1)!.trigger('click')
await flushPromises()
const dialog = wrapper.findComponent(AppDialog)
dialog.vm.$emit('confirm')
await flushPromises()
expect(getPallet).toHaveBeenCalledWith('200', '9007199254740993')
expect(updatePallet).toHaveBeenCalledWith('200', '9007199254740993', expect.objectContaining({
palletCode: 'PLT-1', fbaWarehouseCode: 'ABE3', version: 7,
}))
expect(dialog.props('modelValue')).toBe(true)
expect(createPallet).not.toHaveBeenCalled()
})
it('creates an IDLE ABE3 pallet under the selected Los Angeles warehouse id', async () => {
vi.mocked(createPallet).mockResolvedValueOnce('9007199254740994')
const wrapper = mount(PalletsView, { attachTo: document.body, global: { plugins: [ElementPlus] } })
await flushPromises()
await wrapper.findAll('button').find((button) => button.text().includes('新增托盘'))!.trigger('click')
await flushPromises()
const view = wrapper.vm as unknown as { form: { warehouseId: string; fbaWarehouseCode: string; code: string } }
Object.assign(view.form, { warehouseId: '200', fbaWarehouseCode: 'ABE3', code: 'PLT-LAX-ABE3' })
await flushPromises()
wrapper.findComponent(AppDialog).vm.$emit('confirm')
await flushPromises()
expect(createPallet).toHaveBeenCalledWith('200', expect.objectContaining({
palletCode: 'PLT-LAX-ABE3', fbaWarehouseCode: 'ABE3', status: 'IDLE',
}))
})
})