Files
admin-web/src/modules/overseas-warehouse/components/DispatchLooseboardExecution.test.ts
T
2026-11-02 17:15:37 +08:00

93 lines
6.8 KiB
TypeScript

import ElementPlus from 'element-plus'
import { flushPromises, mount } from '@vue/test-utils'
import { beforeEach, expect, it, vi } from 'vitest'
import DispatchLooseboardExecution from './DispatchLooseboardExecution.vue'
import { getLooseboardExecution, uploadLooseboardPhoto, saveLooseboardPhotos } from '../api/dispatchLooseboardExecution'
import type { LooseboardExecution } from '../api/dispatchLooseboardExecution'
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => true }) }))
vi.mock('../api/dispatchLooseboardExecution', () => ({ getLooseboardExecution: vi.fn(), uploadLooseboardPhoto: vi.fn(), saveLooseboardPhotos: vi.fn(), readLooseboardPhoto: vi.fn() }))
const value = (direct = true): LooseboardExecution => ({ dispatchNo: 'PC1', recordVersion: '3', stage: direct ? 'LOADING' : 'DELIVERING', direct, items: [{ itemId: '101', customerId: '1', orderNo: 'LB1', destination: 'TEST', packages: 2, pickupPhotos: [], arrivalPhotos: [], canPickup: true, canArrive: false }] })
beforeEach(() => { vi.clearAllMocks(); vi.mocked(getLooseboardExecution).mockResolvedValue(value()) })
it('shows pure looseboard photo flow and uploads to its authoritative item and node', async () => {
vi.mocked(uploadLooseboardPhoto).mockResolvedValue({ fileId: '77', fileName: 'pickup.png', contentType: 'image/png', sizeBytes: 10 })
vi.mocked(saveLooseboardPhotos).mockResolvedValue({ ...value(), stage: 'DELIVERING' })
const wrapper = mount(DispatchLooseboardExecution, { props: { dispatchNo: 'PC1' }, global: { plugins: [ElementPlus] } }); await flushPromises()
expect(wrapper.text()).not.toContain('全车为散板')
expect(wrapper.findAll('input[type=file]')).toHaveLength(2)
expect(wrapper.get('input[aria-label="LB1上传送达照片"]').attributes('disabled')).toBeDefined()
const input = wrapper.get('input[type=file]')
Object.defineProperty(input.element, 'files', { value: [new File(['test'], 'pickup.png', { type: 'image/png' })], configurable: true })
await input.trigger('change'); await flushPromises()
expect(uploadLooseboardPhoto).toHaveBeenCalledWith('PC1', '101', 'PICKUP', expect.any(File))
expect(saveLooseboardPhotos).toHaveBeenCalledWith('PC1', '101', 'PICKUP', { recordVersion: '3', idempotencyKey: expect.any(String), fileIds: ['77'] })
expect(wrapper.emitted('saved')).toHaveLength(1); wrapper.unmount()
})
it('keeps pickup upload visible but disabled until mixed warehouse cargo departs', async () => {
const snapshot = value(false)
snapshot.stage = 'LOADING'
snapshot.items[0]!.canPickup = false
vi.mocked(getLooseboardExecution).mockResolvedValue(snapshot)
const wrapper = mount(DispatchLooseboardExecution, { props: { dispatchNo: 'PC1' }, global: { plugins: [ElementPlus] } }); await flushPromises()
expect(wrapper.text()).not.toContain('混排货物按原流程')
expect(wrapper.text()).toContain('上传取货照片')
expect(wrapper.text()).toContain('完成仓内拣货并确认装车后可上传')
const input = wrapper.get('input[aria-label="LB1上传取货照片"]')
expect(input.attributes('disabled')).toBeDefined()
Object.defineProperty(input.element, 'files', { value: [new File(['test'], 'pickup.png', { type: 'image/png' })], configurable: true })
input.element.dispatchEvent(new Event('change', { bubbles: true })); await flushPromises()
expect(uploadLooseboardPhoto).not.toHaveBeenCalled()
wrapper.unmount()
})
it('enables pickup upload for mixed cargo in delivery', async () => {
vi.mocked(getLooseboardExecution).mockResolvedValue(value(false))
const wrapper = mount(DispatchLooseboardExecution, { props: { dispatchNo: 'PC1' }, global: { plugins: [ElementPlus] } }); await flushPromises()
expect(wrapper.get('input[aria-label="LB1上传取货照片"]').attributes('disabled')).toBeUndefined()
wrapper.unmount()
})
it('enables mixed pickup from after loading using server eligibility', async () => {
const snapshot = value(false)
snapshot.stage = 'AFTER_LOADING'
vi.mocked(getLooseboardExecution).mockResolvedValue(snapshot)
const wrapper = mount(DispatchLooseboardExecution, { props: { dispatchNo: 'PC1' }, global: { plugins: [ElementPlus] } }); await flushPromises()
expect(wrapper.get('input[aria-label="LB1上传取货照片"]').attributes('disabled')).toBeUndefined()
expect(wrapper.get('input[aria-label="LB1上传送达照片"]').attributes('disabled')).toBeDefined()
wrapper.unmount()
})
it('keeps upload available after saving and appends multiple files to the current list', async () => {
const snapshot = value(false)
const old = { fileId: '77', fileName: 'old.png', contentType: 'image/png', sizeBytes: 10 }
snapshot.items[0]!.pickupPhotos = [old]
snapshot.items[0]!.canArrive = true
vi.mocked(getLooseboardExecution).mockResolvedValue(snapshot)
vi.mocked(uploadLooseboardPhoto)
.mockResolvedValueOnce({ ...old, fileId: '78', fileName: 'new1.png' })
.mockResolvedValueOnce({ ...old, fileId: '79', fileName: 'new2.png' })
vi.mocked(saveLooseboardPhotos).mockResolvedValue(snapshot)
const wrapper = mount(DispatchLooseboardExecution, { props: { dispatchNo: 'PC1' }, global: { plugins: [ElementPlus] } }); await flushPromises()
const input = wrapper.get('input[aria-label="LB1上传取货照片"]')
expect(input.attributes('disabled')).toBeUndefined()
Object.defineProperty(input.element, 'files', { value: ['new1.png', 'new2.png'].map(name => new File(['test'], name, { type: 'image/png' })), configurable: true })
await input.trigger('change'); await flushPromises()
expect(uploadLooseboardPhoto).toHaveBeenCalledTimes(2)
expect(saveLooseboardPhotos).toHaveBeenCalledWith('PC1', '101', 'PICKUP', expect.objectContaining({ recordVersion: '3', fileIds: ['77', '78', '79'] }))
wrapper.unmount()
})
it('deletes one photo while preserving the others in the versioned save', async () => {
const snapshot = value(false)
const old = { fileId: '77', fileName: 'old.png', contentType: 'image/png', sizeBytes: 10 }
snapshot.items[0]!.pickupPhotos = [old, { ...old, fileId: '78', fileName: 'keep.png' }]
vi.mocked(getLooseboardExecution).mockResolvedValue(snapshot)
const updated = value(false)
updated.items[0]!.pickupPhotos = [snapshot.items[0]!.pickupPhotos[1]!]
vi.mocked(saveLooseboardPhotos).mockResolvedValue(updated)
const wrapper = mount(DispatchLooseboardExecution, { props: { dispatchNo: 'PC1' }, global: { plugins: [ElementPlus] } }); await flushPromises()
await wrapper.get('button[aria-label="删除取货照片old.png"]').trigger('click'); await flushPromises()
expect(saveLooseboardPhotos).toHaveBeenCalledWith('PC1', '101', 'PICKUP', expect.objectContaining({ recordVersion: '3', fileIds: ['78'] }))
expect(wrapper.text()).not.toContain('old.png')
expect(wrapper.text()).not.toContain('keep.png')
expect(wrapper.find('button[aria-label="删除取货照片keep.png"]').exists()).toBe(true)
expect(wrapper.emitted('saved')).toHaveLength(1)
wrapper.unmount()
})