import test from 'node:test' import assert from 'node:assert/strict' import { readFile } from 'node:fs/promises' const source = await readFile(new URL('../api/pda-loading.js', import.meta.url), 'utf8') const page = await readFile(new URL('../pages/picking/picking.vue', import.meta.url), 'utf8') test('PDA loading adapter keeps C04 read and write paths', () => { for (const path of [ '/first-leg/pda-loading/tasks/pending', '/loading/picking?tenantId=', '/loading/picking/start?tenantId=', '/loading/picking/complete?tenantId=', '/loading/evidence/pda?tenantId=', '/loading/complete?tenantId=' ]) assert.match(source, new RegExp(path.replace(/[?]/g, '\\?'))) assert.match(source, /'Idempotency-Key'/) assert.match(source, /PHOTO_STEP_1[\s\S]*PHOTO_STEP_4[\s\S]*SEAL/) for (const label of ['空仓照片', '半仓照片', '满仓照片', '锁仓照片', '带锁码照']) assert.match(source, new RegExp(label)) assert.match(source, /uni\.uploadFile/) assert.match(source, /\/files\/loading-evidence\//) assert.match(source, /loading\/evidence\/pda\?tenantId=/) assert.match(source, /loading\/evidence\/\$\{encodeURIComponent\(evidenceId\)\}\/void\/pda\?tenantId=/) }) test('PDA adapter does not treat non-200 response bodies or network failures as success', () => { assert.match(source, /if \(code !== '200'\)/) assert.match(source, /next\.network = true/) assert.match(source, /throw new Error\('缺少客户隔离标识 tenantId/) }) test('C02 identifiers and separate picking/inbound versions are normalized explicitly', () => { assert.match(source, /inboundId: row\.inboundId/) assert.match(source, /inboundVersion: row\.inboundVersion/) assert.match(source, /pickingVersion: row\.pickingVersion \?\? row\.loading\?\.pickingVersion/) assert.match(source, /pickingVersion: task\.pickingVersion \?\? task\.version/) assert.match(page, /expectedVersion: Number\(this\.pickingVersion\)/) assert.match(page, /ITEM_STATUS, classifyScan, createItemStates, getPickSummary, submitStates/) assert.match(page, /taskItemId: item\.id \?\? item\.itemId/) assert.match(page, /submit\.batch/) assert.match(page, /item\.itemStatus === 'PICKED'/) assert.match(page, /item\.itemStatus === 'PARTIAL'/) assert.match(page, /pickingCompleted \|\| !summary\.canSubmit/) assert.match(page, /this\.loadingVersion = task\.inboundVersion \?\? task\.loadingVersion/) assert.match(page, /状态尚未同步,请刷新重试/) }) test('picking page exposes five evidence slots, retry and remote completion states', () => { for (const text of ['PHOTO_STEP_1', 'PHOTO_STEP_4', 'SEAL', '网络失败', '确认装柜完成', 'loadingVersion']) { assert.match(`${source}\n${page}`, new RegExp(text)) } assert.match(page, /createEvidenceUploadQueue/) assert.match(page, /retryEvidence/) assert.match(page, /uploadEvidenceFile/) assert.match(page, /submitting \|\| completedBoxes\[currentBoxIndex\]/) assert.match(page, /completePicking\(/) assert.match(page, /sourceType: \['camera'\]/) assert.doesNotMatch(page, /sourceType: \['camera', 'album'\]/) assert.match(page, /evidenceEntries\(slot\.type\)/) assert.match(page, /voidEvidencePhoto\(/) assert.match(page, /evidenceComplete/) }) test('PDA cabinet picking adapter claims online and submits one atomic batch', () => { assert.match(source, /\/first-leg\/pda-loading\/tasks\/pending/) assert.match(source, /\/first-leg\/pda-loading\/tasks\?/) assert.match(source, /tasks\/\$\{encodeURIComponent\(taskId\)\}\/claim/) assert.match(source, /tasks\/\$\{encodeURIComponent\(task\.taskId\)\}\/batch/) assert.match(source, /tasks\/\$\{encodeURIComponent\(taskId\)\}\/inventory-snapshot\?warehouseId=/) assert.match(source, /submitContainerPickingBatch/) assert.match(source, /stableIdempotencyKey/) assert.match(source, /Math\.imul\(hash, 16777619\)/) assert.match(source, /slice\(0, 128\)/) assert.match(page, /claimContainerPickingTask\(/) assert.match(page, /submitContainerPickingBatch\(/) assert.match(page, /任务版本已变化,请刷新后重试/) assert.match(source, /data: \{ warehouseId, loadingPlanId: task\.loadingPlanId, containerBookingId: task\.containerBookingId, expectedVersion, inventorySnapshotToken, items \}/) assert.match(source, /cabinetNo=/) assert.match(source, /loadingPlanId=/) assert.doesNotMatch(source, /query\.push\(`containerNo=/) assert.doesNotMatch(page, /getContainerPickingTask\([^\n]*containerNo:/) assert.match(source, /tasks\/\$\{encodeURIComponent\(taskId\)\}\?warehouseId=/) assert.match(source, /currentContainerNo/) assert.match(source, /getPickingInventorySnapshot[\s\S]*?\.then\(normalizeInventorySnapshot\)/) assert.doesNotMatch(source.match(/export async function submitContainerPickingBatch[\s\S]*?\n\}/)?.[0] || '', /containerNo/) assert.doesNotMatch(page, /claim-[^`]*currentBox\.boxNo/) assert.doesNotMatch(page.match(/stableOperationId\('submit'[\s\S]*?\n/)?.[0] || '', /boxNo|containerNo|currentContainerNo/) assert.match(page, /await getPickingInventorySnapshot\([\s\S]*await submitContainerPickingBatch/) assert.match(page, /库存已变化,请刷新后重试/) assert.doesNotMatch(source.match(/export async function submitContainerPickingBatch[\s\S]*?\n\}/)?.[0] || '', /for \(/) assert.match(page, /version: Number\(item\.version \|\| 0\)/) assert.match(page, /refreshTask/) assert.match(page, /remoteError && !pickingCompleted/) assert.match(page, /库存快照未同步,请刷新任务后重试/) assert.match(page, /拣货完成未提交,请查看错误提示/) assert.match(page, /if \(!isPickingCompleteTask\(remoteTask\)\)[\s\S]*claimContainerPickingTask/) assert.match(page, /taskRequestId/) assert.match(page, /resetEvidenceState/) assert.match(page, /availablePickQuantity/) assert.match(page, /库存\/库位可用量不足/) })