127 lines
8.0 KiB
TypeScript
127 lines
8.0 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { readFileSync } from 'node:fs'
|
|
import { resolve } from 'node:path'
|
|
|
|
const source = readFileSync(resolve(process.cwd(), 'src/modules/loading-lists/pages/PreloadPlanDetailView.vue'), 'utf8')
|
|
const detailSource = readFileSync(resolve(process.cwd(), 'src/modules/loading-lists/components/LoadingListDetailDrawer.vue'), 'utf8')
|
|
|
|
describe('PreloadPlanDetailView prototype contract', () => {
|
|
it('is a formal desktop detail page wired to the shared header return action', () => {
|
|
expect(source).toContain('<AdminPage class="admin-workbench admin-density">')
|
|
expect(source).toContain('@back="goBack"')
|
|
expect(source).toContain("router.push({ name: 'loading-plans' })")
|
|
expect(source).toContain('@media (min-width: 1920px) { .preload-detail-page { width: 100%; max-width: none; gap: var(--admin-space-5, 12px); } }')
|
|
expect(source).not.toContain('AppDrawer')
|
|
})
|
|
|
|
it('requires the real warehouse context and preserves status boundaries', () => {
|
|
expect(source).toContain('MISSING_WAREHOUSE_CONTEXT')
|
|
expect(source).toContain("['EDITING', 'LOADING'].includes(result.summary.status)")
|
|
expect(source).toContain('MODE_STATUS_MISMATCH')
|
|
})
|
|
|
|
it('switches a completed preload lifecycle to the confirmed detail without swallowing unrelated errors', () => {
|
|
expect(source).toContain('/loading-plans/${encodeURIComponent(planId.value)}/lifecycle')
|
|
expect(source).toContain("lifecycle.detailResource === 'LOADING_LIST'")
|
|
expect(source).toContain("lifecycle.planStatus !== 'COMPLETED'")
|
|
expect(source).toContain("router.replace({ name: 'domestic-container-detail'")
|
|
expect(source).toContain("workspace.removeByIds(['preload-plan-detail'])")
|
|
expect(source).toContain('装柜已完成,已切换至装柜清单详情')
|
|
expect(source).not.toContain("preloadError.code !== 'A0404'")
|
|
expect(source).toContain('getConfirmedLoadingList')
|
|
expect(source).not.toContain("router.push({ name: 'loading-list-detail'")
|
|
})
|
|
|
|
it('uses the real optimistic-lock transport endpoint without inventing note writes', () => {
|
|
expect(source).toContain('updatePreloadTransport')
|
|
expect(source).toContain('expectedVersion: detail.value.summary.version')
|
|
expect(source).toContain('width="min(620px, calc(100vw - 28px))"')
|
|
expect(source).not.toContain('saveMfNote')
|
|
})
|
|
|
|
it('edits the selected item internal, warehouse and customer-service remarks with optimistic locking', () => {
|
|
expect(source).toContain('@edit-remarks="openRemarks"')
|
|
expect(source).toContain('updateLoadingItemRemarks(current.summary.planId, target.itemId')
|
|
expect(source).toContain('expectedPlanVersion: current.summary.version')
|
|
expect(source).toContain('expectedItemVersion: target.itemVersion')
|
|
expect(source).toContain('operationId: remarkOperationId.value')
|
|
expect(source).toContain('maxlength="1000"')
|
|
expect(source).toContain("remarkForm.internalRemark.trim() || null")
|
|
expect(source).toContain("remarkForm.warehouseRemark.trim() || null")
|
|
expect(source).toContain("remarkForm.customerServiceRemark.trim() || null")
|
|
expect(source).toContain('summary: { ...current.summary, version: result.version }')
|
|
expect(source).toContain('updatedItem?.version')
|
|
expect(source).not.toContain('plan.remark')
|
|
})
|
|
|
|
it('preserves remark input and refreshes current data on conflicts', () => {
|
|
expect(source).toContain("details.code === 'A0409'")
|
|
expect(source).toContain('await loadDetail()')
|
|
expect(source).toContain("detail.value?.items.find((item) => item.itemId === target.itemId) || target")
|
|
expect(source).toContain('当前输入已保留')
|
|
expect(source).toContain('计划状态或明细版本已变化')
|
|
expect(source).toContain(':confirm-loading="remarkSaving"')
|
|
})
|
|
|
|
it('requires first entry before confirmation and still repairs historical tasks that were created without it', () => {
|
|
expect(source).toContain("{ required: true, message: '请输入集装箱号'")
|
|
expect(source).toContain("['EDITING', 'LOADING'].includes(summary.status)")
|
|
expect(source).toContain('if (!summary.containerNo) return true')
|
|
expect(source).not.toContain('summary?.containerNo && summary.status')
|
|
expect(source).not.toContain('transportCorrectionNote')
|
|
expect(detailSource).not.toContain('class="readiness-note transport-note"')
|
|
expect(detailSource).not.toContain('真实集装箱号:</strong>')
|
|
expect(source).toContain("isContainerCorrection.value ? '纠正集装箱号 / 航次' : '补录集装箱号 / 航次'")
|
|
expect(source).toContain("isContainerCorrection.value && !String(value || '').trim() ? new Error('纠错时请输入操作原因')")
|
|
expect(source).toContain("String(value || '').trim().toUpperCase()")
|
|
expect(source).toContain('operationReason: editForm.operationReason.trim() || null')
|
|
expect(detailSource).toContain('v-if="canEditTransport"')
|
|
expect(detailSource).toContain("summary.containerNo || '待补录'")
|
|
expect(detailSource).toContain("CONTAINER_NO_MISSING: '尚未录入真实集装箱号,请先补录后再确认预装'")
|
|
})
|
|
|
|
it('uses a flat blocking note instead of repeated colored page alerts', () => {
|
|
expect(source).not.toContain('<el-alert\n v-if="detail"')
|
|
expect(detailSource).toContain('class="readiness-note"')
|
|
expect(detailSource).toContain('role="status"')
|
|
expect(detailSource).toContain("confirmationStatus !== 'CONFIRMED' && !preloadSummary.readiness.canConfirm")
|
|
expect(detailSource).not.toContain('type="success" :closable="false" show-icon title="整份预装计划已确认"')
|
|
expect(detailSource).toContain('type="primary" :loading="confirmSaving"')
|
|
expect(detailSource).not.toContain('<el-button type="success" :loading="confirmSaving"')
|
|
})
|
|
|
|
it('keeps explanatory notes outside the item list hidden', () => {
|
|
expect(detailSource).not.toContain('核对运输信息、确认预装并维护逐条仓库备注')
|
|
expect(detailSource).not.toContain('仓库备注将随装柜完成资料下发海外仓')
|
|
expect(source).not.toContain('暂无候选,请先配置国内头程 PDA 作业员')
|
|
})
|
|
|
|
it('confirms the whole plan through readiness with stable idempotency and refreshes the detail', () => {
|
|
expect(source).toContain('confirmPreloadPlan(summary.planId, summary.version, assigneeId.value, confirmOperationId.value)')
|
|
expect(source).toContain('listDomesticPdaOperators(warehouseId.value)')
|
|
expect(source).toContain('v-model="assigneeId"')
|
|
expect(source).toContain('<template #pda-operator>')
|
|
expect(detailSource).toContain('<slot v-if="mode === \'preload\'" name="pda-operator" />')
|
|
expect(source).not.toContain('暂无候选,请先配置国内头程 PDA 作业员')
|
|
expect(detailSource).toContain('!pdaAssigneeSelected')
|
|
expect(source).toContain('selectedAssignee?.displayName')
|
|
expect(source).not.toContain('<el-form-item label="国内头程 PDA 作业员(必选)">')
|
|
expect(source).toContain('summary?.readiness.canConfirm')
|
|
expect(source).toContain('confirmSaving.value')
|
|
expect(source).toContain('await loadDetail()')
|
|
expect(source).toContain("preloadDialogTitle('推送PDA')")
|
|
expect(source).not.toContain('本操作将确认整份预装计划')
|
|
expect(source).toContain(':confirm-disabled="!detail?.summary.readiness.canConfirm || !assigneeId || assigneeLoading"')
|
|
expect(source).not.toContain('/inbounds/')
|
|
})
|
|
|
|
it('keeps backend confirmation errors visible and supports narrow dialogs', () => {
|
|
expect(source).toContain("confirmError.value = getApiErrorDetails(cause, '确认预装失败,请稍后重试')")
|
|
expect(source).toContain('<OperationErrorToast :details="remarkError || editError || confirmError" />')
|
|
expect(source).toContain(':message="confirmError.message"')
|
|
expect(source).toContain('width="min(520px, calc(100vw - 28px))"')
|
|
const confirmation = source.match(/<table[^>]*aria-label="确认预装资料"[\s\S]*?<\/table>/)?.[0] || ''
|
|
for (const label of ['预装单号', '柜次号', '集装箱号', 'PDA 操作员']) expect(confirmation).toContain(`<th>${label}</th>`)
|
|
})
|
|
})
|