Files
baiyue-firstleg/scripts/pallet-location-test-env-acceptance.contract.test.mjs

124 lines
5.7 KiB
JavaScript

import assert from 'node:assert/strict'
import { readFile } from 'node:fs/promises'
import test from 'node:test'
import {
PALLET_LOCATION_SCENARIOS,
inspectCrossScenarioIsolation,
inspectScenarioReport,
parseMatrixArguments,
} from './pallet-location-test-env-acceptance.mjs'
const source = await readFile(new URL('./pallet-location-test-env-acceptance.mjs', import.meta.url), 'utf8')
test('pallet location matrix declares deterministic one, two, and three-image scenarios', () => {
assert.equal(PALLET_LOCATION_SCENARIOS.length, 5)
assert.deepEqual(PALLET_LOCATION_SCENARIOS.map((item) => item.expectedPalletCount), [1, 1, 1, 2, 3])
assert.match(source, /--modules', 'orders,inbound-measurement'/)
assert.match(source, /--verify-pallet-location-guide', 'true'/)
assert.match(source, /--wait-split-package-count', '18'/)
assert.match(source, /--wait-split-package-count', '12'/)
assert.match(source, /--route-mode', 'random', '--wait-split-random-value', '2'/)
assert.match(source, /第3张确认后扩容只追加且既有槽身份不漂移/)
assert.match(source, /beforeSlots=1, afterSlots=2/)
assert.match(source, /beforeSlots=2, afterSlots=3/)
})
test('matrix options select known scenarios without duplicate or unknown names', () => {
const parsed = parseMatrixArguments([
'--origin-warehouse-name', '测试仓',
'--scenarios', 'single-image-single-slot,two-image-incremental-growth',
'--output=reports/custom.json',
])
assert.equal(parsed.originWarehouseName, '测试仓')
assert.deepEqual(parsed.scenarioNames, ['single-image-single-slot', 'two-image-incremental-growth'])
assert.equal(parsed.output, 'reports/custom.json')
assert.throws(() => parseMatrixArguments(['--scenarios', 'unknown']), /未知场景/)
assert.throws(() => parseMatrixArguments(['--scenarios', 'measured-volume-growth,measured-volume-growth']), /重复场景/)
})
test('scenario inspection requires deletion release, refill reuse, WAIT_SPLIT, and guide identity', () => {
const scenario = PALLET_LOCATION_SCENARIOS[0]
const requiredNames = [
'删除只解绑图片且原 reservation/location 变为 RESERVED_EMPTY',
'替代图片按新 resultId 复用原空槽',
'固定客户第 1 单停在待分柜',
'报告敏感信息扫描',
]
const report = {
success: true,
marker: 'TEST',
summary: { total: 10, failed: 0 },
createdResources: {
inboundMeasurement: { inboundId: '11', measurementId: '12', palletCount: 1, processStatus: 'WAIT_SPLIT' },
inboundMeasurementLocationGuide: {
inboundId: '11', blockId: '13', reservationId: '14', locationId: '15',
deleteSucceeded: true, slotReused: true,
},
},
steps: [
...requiredNames.map((name) => ({ name, passed: true })),
{ name: '第1张确认后整票库位块计数与槽身份完整', passed: true,
evidence: 'blockId=13, reserved=1, actual=1, empty=0, slots=1' },
],
}
const inspected = inspectScenarioReport(scenario, report, 0)
assert.equal(inspected.passed, true)
report.steps.find((step) => step.name.startsWith('删除只解绑')).passed = false
assert.equal(inspectScenarioReport(scenario, report, 0).passed, false)
})
test('scenario inspection detects naturally observed shared A0 from evidence without coupling to step wording', () => {
const scenario = PALLET_LOCATION_SCENARIOS[0]
const report = {
success: false,
createdResources: {},
steps: [{ name: '正式数据 A0 共享溢出观测', passed: true,
evidence: 'sharedOverflow=true, slots=1:reservation:A0' }],
}
assert.equal(inspectScenarioReport(scenario, report, 1).resources.sharedOverflowObserved, true)
})
test('three-image scenario rejects a no-op growth assertion even when the base step passed', () => {
const scenario = PALLET_LOCATION_SCENARIOS.at(-1)
const report = {
success: true,
createdResources: {
inboundMeasurement: { palletCount: 3, processStatus: 'WAIT_SPLIT' },
inboundMeasurementLocationGuide: {
blockId: '1', reservationId: '2', locationId: '3', deleteSucceeded: true, slotReused: true,
},
},
steps: [
{ name: '删除只解绑图片且原 reservation/location 变为 RESERVED_EMPTY', passed: true },
{ name: '替代图片按新 resultId 复用原空槽', passed: true },
{ name: '固定客户第 1 单停在待分柜', passed: true },
{ name: '报告敏感信息扫描', passed: true },
{ name: '第2张确认后扩容只追加且既有槽身份不漂移', passed: true,
evidence: 'beforeSlots=3, afterSlots=3' },
{ name: '第3张确认后扩容只追加且既有槽身份不漂移', passed: true,
evidence: 'beforeSlots=3, afterSlots=3' },
],
}
const inspected = inspectScenarioReport(scenario, report, 0)
assert.equal(inspected.assertions.requiredStepEvidence, false)
assert.deepEqual(inspected.mismatchedStepEvidence, scenario.requiredSteps)
})
test('cross-scenario inspection permits shared A0 location but rejects shared reservation or block', () => {
const results = [
{ resources: { inboundId: '1', blockId: '11', reservationId: '21', locationId: 'A0' } },
{ resources: { inboundId: '2', blockId: '12', reservationId: '22', locationId: 'A0' } },
]
assert.equal(inspectCrossScenarioIsolation(results).passed, true)
results[1].resources.reservationId = '21'
assert.equal(inspectCrossScenarioIsolation(results).passed, false)
})
test('matrix does not disable locations, execute SQL, deploy, or use a shell child process', () => {
assert.doesNotMatch(source, /location-status|batch-disable|UPDATE\s+|DELETE\s+FROM|INSERT\s+INTO/i)
assert.doesNotMatch(source, /jenkins|docker\s+compose|kubectl/i)
assert.match(source, /shell: false/)
assert.match(source, /A0 仅在普通库位自然不足时观测/)
})