优化
This commit is contained in:
@@ -1,40 +1,80 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
import ElementPlus from 'element-plus'
|
||||
import { flushPromises, mount, type VueWrapper } from '@vue/test-utils'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import ContainerDetailView from './ContainerDetailView.vue'
|
||||
import { getContainer, getContainerClearance, getContainerOverview, uploadContainerClearance, uploadContainerDocument } from '../api/platformContainerLoading'
|
||||
import { uploadLoadingDeclaration } from '@/modules/loading-lists'
|
||||
|
||||
const source = readFileSync(resolve(process.cwd(), 'src/modules/container-loading/pages/ContainerDetailView.vue'), 'utf8')
|
||||
const { accessCan, routerPush } = vi.hoisted(() => ({ accessCan: vi.fn(), routerPush: vi.fn() }))
|
||||
vi.mock('vue-router', () => ({ useRoute: () => ({ params: { containerId: '2092438843630391297' }, query: {} }), useRouter: () => ({ push: routerPush }) }))
|
||||
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: accessCan }) }))
|
||||
vi.mock('@/modules/port-schedules', () => ({ CarrierScheduleQueryPanel: { template: '<div data-test="carrier-panel" />' } }))
|
||||
vi.mock('@/modules/loading-lists', () => ({ uploadLoadingDeclaration: vi.fn() }))
|
||||
vi.mock('../api/platformContainerLoading', () => ({
|
||||
getContainer: vi.fn(), getContainerOverview: vi.fn(), getContainerClearance: vi.fn(),
|
||||
uploadContainerClearance: vi.fn(), completeContainerClearance: vi.fn(), uploadContainerDocument: vi.fn(),
|
||||
downloadContainerDocument: vi.fn(), downloadContainerPdaPhoto: vi.fn(), markContainerException: vi.fn(), cancelContainerException: vi.fn(),
|
||||
}))
|
||||
|
||||
const detail = { id: '2092438843630391297', planId: '2092438843630391401', planNo: 'LP-260825-0181', bookingNo: 'CB-1', cabinetNo: 'CAB-1', containerNo: 'C11111111', warehouseId: '193000000000200002', warehouseName: '东莞仓', containerType: '45HC', planStatus: 'COMPLETED', version: 8 } as never
|
||||
const overview = {
|
||||
container: { id: '2092438843630391297', bookingNo: 'CB-1', cabinetNo: 'CAB-1', containerNo: 'C11111111', status: 'COMPLETED', warehouseId: '193000000000200002', warehouseName: '东莞仓', voyageNo: null, vesselName: null, version: 8 },
|
||||
loadingPlanId: '2092438843630391401', pda: null,
|
||||
documents: [{ id: '2092438843630391501', documentType: 'CUSTOMS_DECLARATION', fileId: '2092438843630391502', fileName: 'old.pdf', fileHash: null, uploadedBy: '1', uploadedByName: '操作员', uploadedAt: '2026-08-26T10:00:00', version: 5, completed: false }],
|
||||
exception: { active: false, reason: null, markedBy: null, markedByName: null, markedAt: null }, exceptionHistory: [], timeline: [],
|
||||
}
|
||||
|
||||
function mountView(customs = true) {
|
||||
accessCan.mockImplementation((permission: string) => permission === 'platform:firstleg:container:edit' || (customs && permission === 'platform:firstleg:customs:manage'))
|
||||
return mount(ContainerDetailView, { global: { plugins: [ElementPlus] } })
|
||||
}
|
||||
function documentArticle(wrapper: VueWrapper, label: string) { return wrapper.findAll('.document-item').find((item) => item.text().includes(label))! }
|
||||
|
||||
describe('ContainerDetailView', () => {
|
||||
it('keeps identity, status and key facts in a compact overview', () => {
|
||||
expect(source).toContain('class="container-overview surface-panel"')
|
||||
expect(source).toContain('class="container-overview__header"')
|
||||
expect(source).toContain('class="container-overview__summary"')
|
||||
expect(source).toContain('grid-template-columns:repeat(5,minmax(0,1fr))')
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
vi.mocked(getContainer).mockResolvedValue(detail)
|
||||
vi.mocked(getContainerOverview).mockResolvedValue(overview as never)
|
||||
vi.mocked(getContainerClearance).mockResolvedValue(null)
|
||||
vi.mocked(uploadLoadingDeclaration).mockResolvedValue({} as never)
|
||||
vi.mocked(uploadContainerDocument).mockResolvedValue({} as never)
|
||||
vi.mocked(uploadContainerClearance).mockResolvedValue({} as never)
|
||||
})
|
||||
|
||||
it('keeps real document, exception and authorized photo operations', () => {
|
||||
expect(source).toContain('uploadContainerDocument(')
|
||||
expect(source).toContain('downloadContainerDocument(')
|
||||
expect(source).toContain('uploadContainerClearance(')
|
||||
expect(source).toContain('completeContainerClearance(')
|
||||
expect(source).toContain('markContainerException')
|
||||
expect(source).toContain('cancelContainerException')
|
||||
expect(source).toContain('downloadContainerPdaPhoto(photo.downloadPath)')
|
||||
it('opens domestic export customs upload and sends stable plan, warehouse, version and reason', async () => {
|
||||
const wrapper = mountView(); await flushPromises()
|
||||
await documentArticle(wrapper, '国内出口报关附件').find('button').trigger('click'); await flushPromises()
|
||||
expect(wrapper.text()).toContain('国内出口报关附件')
|
||||
const file = new File(['customs'], 'customs.pdf', { type: 'application/pdf' })
|
||||
;(wrapper.vm as unknown as { selectDocumentFile: (file: { raw: File }) => void }).selectDocumentFile({ raw: file })
|
||||
await (wrapper.vm as unknown as { saveDocument: () => Promise<void> }).saveDocument()
|
||||
expect(uploadLoadingDeclaration).toHaveBeenCalledWith('2092438843630391401', '193000000000200002', file, 5, '上传国内出口报关附件')
|
||||
expect(uploadContainerDocument).not.toHaveBeenCalled(); expect(uploadContainerClearance).not.toHaveBeenCalled()
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('carries the existing read-only CarrierScheduleQuery by booking and container', () => {
|
||||
expect(source).toContain('CarrierScheduleQueryPanel')
|
||||
expect(source).toContain("from '@/modules/port-schedules'")
|
||||
expect(source).toContain(':ocean-booking-id="detail.oceanBookingId"')
|
||||
expect(source).toContain(':container-booking-id="detail.id"')
|
||||
it('shows a readable error when the container has no loading plan', async () => {
|
||||
vi.mocked(getContainerOverview).mockResolvedValueOnce({ ...overview, loadingPlanId: null } as never)
|
||||
const wrapper = mountView(); await flushPromises()
|
||||
await documentArticle(wrapper, '国内出口报关附件').find('button').trigger('click'); await flushPromises()
|
||||
expect(wrapper.text()).toContain('当前货柜没有装柜清单,无法上传国内出口报关附件')
|
||||
expect(uploadLoadingDeclaration).not.toHaveBeenCalled(); wrapper.unmount()
|
||||
})
|
||||
|
||||
it('shows overseas unloading and empty-report facts without adding upload or PDA actions', () => {
|
||||
expect(source).toContain('detail.unloadingCompletedAt')
|
||||
expect(source).toContain('detail.unloadingPhotoUploadedAt')
|
||||
expect(source).toContain('detail.estimatedEmptyReportedAt')
|
||||
expect(source).toContain('detail.actualEmptyReportedAt')
|
||||
expect(source).not.toContain('uploadUnloadingPhoto')
|
||||
expect(source).not.toContain('submitEmptyReport')
|
||||
it('hides customs and clearance upload without customs manage permission while keeping DO and PU', async () => {
|
||||
const wrapper = mountView(false); await flushPromises()
|
||||
expect(documentArticle(wrapper, '国内出口报关附件').find('button').exists()).toBe(false)
|
||||
expect(documentArticle(wrapper, '目的港清关资料').find('button').exists()).toBe(false)
|
||||
expect(documentArticle(wrapper, 'DO 资料').find('button').exists()).toBe(true)
|
||||
expect(documentArticle(wrapper, 'PU 资料').find('button').exists()).toBe(true)
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('keeps destination clearance on its independent container clearance API', async () => {
|
||||
const wrapper = mountView(); await flushPromises()
|
||||
await documentArticle(wrapper, '目的港清关资料').find('button').trigger('click'); await flushPromises()
|
||||
expect(getContainerClearance).toHaveBeenCalledWith('2092438843630391297')
|
||||
expect(wrapper.text()).toContain('目的港清关资料'); expect(uploadLoadingDeclaration).not.toHaveBeenCalled()
|
||||
wrapper.unmount()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user