@@ -1,14 +1,15 @@
import ElementPlus , { ElCheckboxButton , ElInputNumber , ElMessage , ElMessageBox , ElOption , ElSelect } from 'element-plus'
import { AxiosError } from 'axios'
import { createPinia , setActivePinia } from 'pinia'
import { flushPromises , mount } from '@vue/test-utils'
import { beforeEach , describe , expect , it , vi } from 'vitest'
import { DOMWrapper , enableAutoUnmount , flushPromises , mount } from '@vue/test-utils'
import { afterEach , beforeEach , describe , expect , it , vi } from 'vitest'
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import QueryToolbar from '@/shared/components/QueryToolbar.vue'
import { listPlatformTenants , type PlatformTenantResource } from '@/modules/iam'
import GlobalSmartLoadingView from './GlobalSmartLoadingView.vue'
import AppDialog from '@/shared/components/AppDialog.vue'
import SmartLoadingDialog from '../components/SmartLoadingDialog.vue'
import type { ContainerBookingResource } from '../types'
import {
assignPendingReviewSmartLoadingOrder ,
@@ -27,6 +28,8 @@ import {
removeSmartLoadingPallet ,
} from '../api/platformContainerLoading'
enableAutoUnmount ( afterEach )
const { routerPush } = vi . hoisted ( ( ) = > ( { routerPush : vi.fn ( ) } ) )
vi . mock ( 'vue-router' , ( ) = > ( {
@@ -120,7 +123,50 @@ function mockContainerSearch(records: ContainerBookingResource[]) {
) ) ) )
}
function assignmentDialog() {
const root = document . body . querySelector < HTMLElement > ( '.smart-loading-assignment-dialog' )
if ( ! root ) throw new Error ( 'assignment dialog is missing' )
return new DOMWrapper ( root )
}
describe ( 'GlobalSmartLoadingView' , ( ) = > {
it ( 'mounts assignment outside the parent workbench and keeps fullscreen and reopen states independent' , async ( ) = > {
const wrapper = mount ( SmartLoadingDialog , { attachTo : document.body , props : { modelValue : true } , global : { plugins : [ ElementPlus ] } } )
try {
await flushPromises ( )
const workbench = wrapper . getComponent ( GlobalSmartLoadingView )
const openAssignment = async ( ) = > {
await workbench . get ( '.candidate-pane .el-table__body-wrapper' ) . findAll ( 'button' ) . find ( button = > button . text ( ) === '加入' ) ! . trigger ( 'click' )
await flushPromises ( )
}
await openAssignment ( )
const popup = workbench . getComponent ( AppDialog )
const outer = document . querySelector ( '.smart-loading-dialog' ) !
const child = assignmentDialog ( )
expect ( document . body . contains ( child . element ) ) . toBe ( true )
expect ( outer . contains ( child . element ) ) . toBe ( false )
expect ( child . element . closest ( '.global-loading-page' ) ) . toBeNull ( )
expect ( child . classes ( ) ) . toEqual ( expect . arrayContaining ( [ 'admin-density-dialog' , 'admin-workbench' , 'is-dialog' ] ) )
popup . getComponent ( ElInputNumber ) . vm . $emit ( 'update:modelValue' , 4 )
await child . get ( '[aria-label="展开全屏"]' ) . trigger ( 'click' )
expect ( child . classes ( ) ) . toContain ( 'is-fullscreen' )
expect ( outer . classList . contains ( 'is-fullscreen' ) ) . toBe ( true )
await child . findAll ( 'button' ) . find ( button = > button . text ( ) === '取消' ) ! . trigger ( 'click' )
await flushPromises ( )
expect ( popup . props ( 'modelValue' ) ) . toBe ( false )
expect ( wrapper . getComponent ( AppDialog ) . props ( 'modelValue' ) ) . toBe ( true )
expect ( workbench . get ( '.container-option.selected' ) . attributes ( 'aria-pressed' ) ) . toBe ( 'true' )
await openAssignment ( )
expect ( popup . props ( 'modelValue' ) ) . toBe ( true )
expect ( assignmentDialog ( ) . classes ( ) ) . not . toContain ( 'is-fullscreen' )
expect ( popup . getComponent ( ElInputNumber ) . props ( 'modelValue' ) ) . toBe ( candidate . availablePackageCount )
expect ( outer . classList . contains ( 'is-fullscreen' ) ) . toBe ( true )
expect ( assignSmartLoadingItem ) . not . toHaveBeenCalled ( )
} finally {
wrapper . unmount ( )
}
} )
it . each ( [ 'PACKAGE' , 'SEALED_PALLET' ] as const ) ( '分配窗口全屏保留来源及输入,按%s原接口提交' , async ( unitType ) = > {
if ( unitType === 'SEALED_PALLET' ) {
vi . mocked ( listSmartLoadingCandidates ) . mockResolvedValue ( candidatePage ( [ {
@@ -138,7 +184,7 @@ describe('GlobalSmartLoadingView', () => {
await wrapper . get ( '.candidate-pane .el-table__body-wrapper' ) . findAll ( 'button' ) . find ( button = > button . text ( ) === '加入' ) ! . trigger ( 'click' )
await flushPromises ( )
const popup = wrapper . getComponent ( AppDialog )
expect ( popup . get ( 'table[aria-label="全局装柜分配来源"]' ) . text ( ) ) . toContain ( 'CB-1' )
expect ( assignmentDialog ( ) . get ( 'table[aria-label="全局装柜分配来源"]' ) . text ( ) ) . toContain ( 'CB-1' )
if ( unitType === 'PACKAGE' ) {
const input = popup . getComponent ( ElInputNumber )
expect ( input . props ( 'modelValue' ) ) . toBe ( candidate . availablePackageCount )
@@ -146,11 +192,11 @@ describe('GlobalSmartLoadingView', () => {
input . vm . $emit ( 'update:modelValue' , 4 )
} else {
expect ( popup . findComponent ( ElInputNumber ) . exists ( ) ) . toBe ( false )
expect ( popup . get ( 'details' ) . text ( ) ) . toContain ( 'I181: 9 箱' )
expect ( assignmentDialog ( ) . get ( 'details' ) . text ( ) ) . toContain ( 'I181: 9 箱' )
expect ( popup . props ( 'title' ) ) . toBe ( '整托加入当前柜次 · DP-TEST-1' )
}
await popup . get ( '[aria-label="展开全屏"]' ) . trigger ( 'click' )
expect ( popup . find ( '.el-dialog.is-fullscreen' ) . exists ( ) ) . toBe ( true )
await assignmentDialog ( ) . get ( '[aria-label="展开全屏"]' ) . trigger ( 'click' )
expect ( assignmentDialog ( ) . classes ( ) ) . toContain ( 'is-fullscreen' )
if ( unitType === 'PACKAGE' ) expect ( popup . getComponent ( ElInputNumber ) . props ( 'modelValue' ) ) . toBe ( 4 )
popup . vm . $emit ( 'confirm' ) ; await flushPromises ( )
if ( unitType === 'PACKAGE' ) {
@@ -572,11 +618,11 @@ describe('GlobalSmartLoadingView', () => {
expect ( document . body . textContent ) . toContain ( '不能部分输入、单独分配或单独移除' )
const popup = wrapper . getComponent ( AppDialog )
expect ( popup . props ( 'title' ) ) . toBe ( '整组加入当前柜次 · CLG-2093539779795795969' )
const contextRows = popup . findAll ( 'table[aria-label="全局装柜分配来源"] tr' )
const contextRows = assignmentDialog ( ) . findAll ( 'table[aria-label="全局装柜分配来源"] tr' )
expect ( contextRows [ 0 ] ! . findAll ( 'td' ) . map ( cell = > cell . text ( ) ) ) . toEqual ( [ 'CB-1' , 'MSCU-1' ] )
expect ( contextRows [ 1 ] ! . findAll ( 'td' ) . map ( cell = > cell . text ( ) ) ) . toEqual ( [ '义乌仓' , '美森正班' ] )
await popup . get ( '[aria-label="展开全屏"]' ) . trigger ( 'click' )
expect ( popup . get ( 'table[aria-label="全局装柜同柜组成员"]' ) . text ( ) ) . toContain ( 'NYEXX2608290051-B' )
await assignmentDialog ( ) . get ( '[aria-label="展开全屏"]' ) . trigger ( 'click' )
expect ( assignmentDialog ( ) . get ( 'table[aria-label="全局装柜同柜组成员"]' ) . text ( ) ) . toContain ( 'NYEXX2608290051-B' )
expect ( document . body . textContent ) . not . toContain ( '本次分配箱数' )
; ( [ . . . document . body . querySelectorAll ( 'button' ) ] . find ( ( button ) = > button . textContent ? . includes ( '确认整组分配' ) ) as HTMLButtonElement ) . click ( )
await flushPromises ( )
@@ -612,9 +658,9 @@ describe('GlobalSmartLoadingView', () => {
await flushPromises ( )
const popup = wrapper . getComponent ( AppDialog )
expect ( popup . props ( 'title' ) ) . toBe ( '加入当前柜次 · EXXHK2609020361' )
const measurements = popup . findAll ( 'table[aria-label="全局装柜分配填写"] tr' ) . find ( row = > row . text ( ) . includes ( '平均单箱毛重' ) ) !
const measurements = assignmentDialog ( ) . findAll ( 'table[aria-label="全局装柜分配填写"] tr' ) . find ( row = > row . text ( ) . includes ( '平均单箱毛重' ) ) !
expect ( measurements . findAll ( 'td' ) . map ( cell = > cell . text ( ) ) ) . toEqual ( [ '待测量' , '待测量' ] )
const channel = popup . findAll ( 'table[aria-label="全局装柜分配来源"] tr' ) . find ( row = > row . text ( ) . includes ( '订单渠道' ) ) !
const channel = assignmentDialog ( ) . findAll ( 'table[aria-label="全局装柜分配来源"] tr' ) . find ( row = > row . text ( ) . includes ( '订单渠道' ) ) !
expect ( channel . findAll ( 'td' ) [ 0 ] ! . text ( ) ) . toBe ( '合德海卡' )
expect ( document . body . textContent ) . toContain ( '这是人工装柜分配,确认后仍会加入' )
expect ( document . body . textContent ) . toContain ( '智能推荐不会跨渠道' )
@@ -907,10 +953,10 @@ describe('GlobalSmartLoadingView', () => {
await flushPromises ( )
// 箱数与上方资料使用同一标签列,保留输入名称与原范围。
const label = popup . get ( 'label[for="global-loading-assignment-count"]' )
const label = assignmentDialog ( ) . get ( 'label[for="global-loading-assignment-count"]' )
expect ( label . element . parentElement ? . tagName ) . toBe ( 'TH' )
expect ( label . element . parentElement ? . nextElementSibling ? . getAttribute ( 'colspan' ) ) . toBe ( '3' )
expect ( popup . find ( 'input#global-loading-assignment-count' ) . exists ( ) ) . toBe ( true )
expect ( assignmentDialog ( ) . find ( 'input#global-loading-assignment-count' ) . exists ( ) ) . toBe ( true )
expect ( input . props ( 'max' ) ) . toBe ( candidate . availablePackageCount )
popup . vm . $emit ( 'confirm' )
await flushPromises ( )
@@ -918,11 +964,12 @@ describe('GlobalSmartLoadingView', () => {
expect ( assignSmartLoadingItem ) . toHaveBeenCalledWith ( plan . id , { inboundId : candidate.inboundId , packageCount : 7 , expectedVersion : plan.version } )
expect ( popup . props ( 'modelValue' ) ) . toBe ( true )
expect ( input . props ( 'modelValue' ) ) . toBe ( 7 )
expect ( popup . text ( ) ) . toContain ( '加入当前柜次失败' )
expect ( popup . text ( ) ) . toContain ( '当前账号无权访问该数据' )
expect ( popup . text ( ) ) . toContain ( 'assign-request' )
expect ( popup . text ( ) ) . toContain ( 'assign-trace' )
expect ( wrapper . get ( '.global-loading-page' ) . findAll ( '.load-error-state' ) ) . toHaveLength ( 1 )
expect ( assignmentDialog ( ) . text ( ) ) . toContain ( '加入当前柜次失败' )
expect ( assignmentDialog ( ) . text ( ) ) . toContain ( '当前账号无权访问该数据' )
expect ( assignmentDialog ( ) . text ( ) ) . toContain ( 'assign-request' )
expect ( assignmentDialog ( ) . text ( ) ) . toContain ( 'assign-trace' )
expect ( assignmentDialog ( ) . findAll ( '.load-error-state' ) ) . toHaveLength ( 1 )
expect ( wrapper . get ( '.global-loading-page' ) . findAll ( '.load-error-state' ) ) . toHaveLength ( 0 )
wrapper . unmount ( )
} )