fix(pda): isolate loading evidence by cabinet context
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
|
||||
const page = await readFile(new URL('../pages/picking/picking.vue', import.meta.url), 'utf8')
|
||||
|
||||
test('loading evidence is mounted only after the current picking task is complete', () => {
|
||||
assert.match(page, /v-if="currentBox\.inboundId && pickingCompleted" class="loading-evidence-section"/)
|
||||
assert.match(page, /isPickingCompleteTask\(task\)[\s\S]*?AWAITING_REVIEW[\s\S]*?COMPLETED/)
|
||||
assert.match(page, /pickingCompleted\(\)[\s\S]*?completedBoxes\[this\.currentBoxIndex\][\s\S]*?isPickingCompleteTask\(this\.remotePick\)/)
|
||||
assert.doesNotMatch(page, /class="loading-evidence-section" v-if="currentBox\.inboundId"/)
|
||||
})
|
||||
|
||||
test('loading evidence is not requested before picking completion', () => {
|
||||
assert.match(page, /if \(this\.pickingCompleted\) await this\.loadLoadingEvidence\(\)/)
|
||||
const loader = page.match(/async loadLoadingEvidence\(\) \{[\s\S]*?\n\t\t\t\},/)?.[0] || ''
|
||||
assert.match(loader, /if \(!this\.pickingCompleted/)
|
||||
assert.match(loader, /await getEvidence\(/)
|
||||
assert.match(page, /this\.completedBoxes = \{[\s\S]*?this\.loadLoadingEvidence\(\)/)
|
||||
})
|
||||
|
||||
test('operators receive actionable refresh guidance without internal version wording', () => {
|
||||
assert.match(page, /状态尚未同步,请刷新重试/)
|
||||
assert.doesNotMatch(page, /缺少拣货版本号|提供装柜版本号/)
|
||||
const complete = page.match(/async completeLoadingTask\(\) \{[\s\S]*?\n\t\t\t\},/)?.[0] || ''
|
||||
assert.match(complete, /if \(!this\.requireEvidenceStage\(\)\) return/)
|
||||
})
|
||||
|
||||
test('evidence mutations defensively reject calls before picking completion', () => {
|
||||
assert.match(page, /requireEvidenceStage\(\)[\s\S]*?if \(this\.pickingCompleted\) return true[\s\S]*?请先提交拣货完成/)
|
||||
for (const method of ['chooseEvidence', 'queueEvidenceUpload', 'retryEvidence', 'saveEvidence', 'saveSealNo', 'voidEvidencePhoto', 'completeLoadingTask']) {
|
||||
const body = page.match(new RegExp(`(?:async )?${method}\\([^)]*\\) \\{[\\s\\S]*?\\n\\t\\t\\t\\},`))?.[0] || ''
|
||||
assert.match(body, /if \(!this\.requireEvidenceStage\(\)\) return/, `${method} should guard the evidence stage`)
|
||||
}
|
||||
})
|
||||
|
||||
test('switching cabinets invalidates old sync and evidence upload state', () => {
|
||||
const selector = page.match(/selectBox\(index\) \{[\s\S]*?\n\t\t\t\},/)?.[0] || ''
|
||||
assert.match(selector, /this\.taskRequestId \+= 1/)
|
||||
assert.match(selector, /this\.pickingVersion = null/)
|
||||
assert.match(selector, /this\.loadingVersion = null/)
|
||||
assert.match(selector, /this\.submitting = false/)
|
||||
assert.match(selector, /this\.resetEvidenceState\(\)/)
|
||||
assert.match(page, /contextId !== this\.evidenceContextId \|\| queue !== this\.evidenceQueue/)
|
||||
const loader = page.match(/async loadLoadingEvidence\(\) \{[\s\S]*?\n\t\t\t\},/)?.[0] || ''
|
||||
assert.equal((loader.match(/contextId !== this\.evidenceContextId/g) || []).length, 2)
|
||||
})
|
||||
|
||||
test('camera callbacks cannot append evidence after switching cabinets', () => {
|
||||
const chooser = page.match(/chooseEvidence\(slot\) \{[\s\S]*?\n\t\t\t\},/)?.[0] || ''
|
||||
assert.match(chooser, /const contextId = this\.evidenceContextId/)
|
||||
assert.match(chooser, /const inboundId = this\.currentBox\.inboundId/)
|
||||
assert.equal((chooser.match(/isEvidenceContextActive\(contextId, inboundId\)/g) || []).length, 2)
|
||||
assert.match(chooser, /isEvidenceContextActive\(contextId, inboundId\)[\s\S]*?this\.evidenceFiles =/)
|
||||
})
|
||||
|
||||
test('evidence save, void and loading completion ignore stale cabinet responses', () => {
|
||||
for (const [method, awaitedCall] of [
|
||||
['saveEvidence', 'upsertEvidence'],
|
||||
['voidEvidencePhoto', 'voidEvidence'],
|
||||
['completeLoadingTask', 'completeLoading']
|
||||
]) {
|
||||
const body = page.match(new RegExp(`async ${method}\\([^)]*\\) \\{[\\s\\S]*?\\n\\t\\t\\t\\},`))?.[0] || ''
|
||||
assert.match(body, /const contextId = this\.evidenceContextId/, `${method} should capture the evidence context`)
|
||||
assert.match(body, /const inboundId = this\.currentBox\.inboundId/, `${method} should capture stable inbound identity`)
|
||||
assert.match(body, new RegExp(`await ${awaitedCall}\\([\\s\\S]*?if \\(!this\\.isEvidenceContextActive\\(contextId, inboundId\\)\\) return`), `${method} should guard the success writeback`)
|
||||
assert.ok((body.match(/isEvidenceContextActive\(contextId, inboundId\)/g) || []).length >= 2, `${method} should guard success and error writebacks`)
|
||||
}
|
||||
const complete = page.match(/async completeLoadingTask\([^)]*\) \{[\s\S]*?\n\t\t\t\},/)?.[0] || ''
|
||||
assert.match(complete, /finally \{[\s\S]*?isEvidenceContextActive\(contextId, inboundId\)[\s\S]*?this\.submitting = false/)
|
||||
})
|
||||
|
||||
test('completed server tasks restore evidence stage without being claimed again', () => {
|
||||
assert.match(page, /const remoteTask = normalizePickingTask\(task\)/)
|
||||
assert.match(page, /if \(!isPickingCompleteTask\(remoteTask\)\) \{[\s\S]*?claimContainerPickingTask/)
|
||||
assert.match(page, /if \(this\.pickingCompleted\) await this\.loadLoadingEvidence\(\)/)
|
||||
})
|
||||
Reference in New Issue
Block a user