Files
pda-overseas-uniapp/tests/relabel-pallet-measurement.test.mjs
T
2026-10-16 18:26:06 +08:00

126 lines
7.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import test from 'node:test'
import assert from 'node:assert/strict'
import { readFile } from 'node:fs/promises'
import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'
const source = await readFile(new URL('../src/components/RelabelPalletWork.vue', import.meta.url), 'utf8')
const script = source.split('<script>')[1].split('</script>')[0].replace(/^import .*$/gm, '').replace('export default', 'return')
function setup() {
const calls = []
const component = new Function('ScanTargetInput', 'measureRelabelPallet', 'warehouseIdempotencyKey', 'releaseWarehouseKey', 'bindRelabelPallet', script)(
{}, async payload => { calls.push(payload); return [{ palletCode: payload.palletCode, volumeCbm: 0.25, grossWeightKg: payload.grossWeightKg }] },
() => ({ value: 'stable-key', signature: 'signature' }), () => {}, async payload => calls.push(payload))
const value = { ...component.data(), task: { relabelNo: 'RL-1' }, $emit() {} }
for (const [key, method] of Object.entries(component.methods)) value[key] = method.bind(value)
return { component, value, calls }
}
test('pallet measurement submits actual dimensions, weight and current stock version and refreshes results', async () => {
const { value, calls } = setup()
await value.saveMeasurement({ palletCode: 'NEW', stockVersion: 'position:version:count', lengthCm: '100', widthCm: '50', heightCm: '50', grossWeightKg: '40' })
assert.deepEqual(calls, [{ relabelNo: 'RL-1', palletCode: 'NEW', stockVersion: 'position:version:count', lengthCm: 100, widthCm: 50, heightCm: 50, grossWeightKg: 40, idempotencyKey: 'stable-key' }])
assert.equal(value.measurements[0].volumeCbm, 0.25)
assert.equal(value.busy, false)
await value.saveMeasurement({ palletCode: 'NEW', lengthCm: 0, widthCm: 50, heightCm: 50, grossWeightKg: 40 })
assert.equal(calls.length, 1)
assert.match(value.error, /有效/)
})
test('only whole physical pallet quantities offer original pallet reuse', () => {
const { component } = setup()
const canRetain = component.computed.canRetainOriginal
const ctx = { source: { totalPackages: 10 }, selectedSource: {}, plannedPackages: 10, isReturnBulk: false, unboundSourceMode: false }
assert.equal(canRetain.call(ctx), true)
ctx.plannedPackages = 4
assert.equal(canRetain.call(ctx), false)
ctx.plannedPackages = 10;ctx.isReturnBulk = true
assert.equal(canRetain.call(ctx), false)
})
async function renderMeasurements(measurements) {
const { component } = setup()
const template = source.slice(source.indexOf('<template>') + 10, source.indexOf('<script>')).trim().replace(/<\/template>$/, '')
return renderToString(createSSRApp({ ...component, template,
components: { ScanTargetInput: { template: '<view />' } },
props: undefined,
data() { return { ...component.data(), task: { relabelNo: 'RL-1', items: [], history: [] }, measurements } }
}))
}
test('unchanged source renders real grouped box specs and totals without zero pallet dimension inputs', async () => {
const html = await renderMeasurements([
{ palletCode: 'FIRST', packages: 2, inherited: true, lengthCm: null, widthCm: null, heightCm: null,
grossWeightKg: 5, volumeCbm: 0.3, sourceCartonSpecs: [{ lengthCm: 60, widthCm: 50, heightCm: 50, grossWeightKg: 2.5, cartons: 2 }] },
{ palletCode: 'SECOND', packages: 3, inherited: true, lengthCm: null, widthCm: null, heightCm: null,
grossWeightKg: 9.7, volumeCbm: 0.31, sourceCartonSpecs: [
{ lengthCm: 60, widthCm: 50, heightCm: 50, grossWeightKg: 2.5, cartons: 1 },
{ lengthCm: 50, widthCm: 40, heightCm: 40, grossWeightKg: 3.6, cartons: 2 }] }
])
assert.match(html, /60 × 50 × 50 cm · 2.5 kg\/箱 · 2 箱/)
assert.match(html, /50 × 40 × 40 cm · 3.6 kg\/箱 · 2 箱/)
assert.match(html, /来源汇总:0.31 m³ · 9.7 kg/)
assert.doesNotMatch(html, /未测整托长宽高/)
assert.equal((html.match(/class="measurement-inputs"/g) || []).length, 0)
assert.doesNotMatch(html, /确认本托实测/)
})
test('changed pallets and explicit packaging changes still render final pallet measurement inputs', async () => {
for (const pallet of [{ inherited: false }, { inherited: true, remeasuring: true }]) {
const html = await renderMeasurements([{ ...pallet, palletCode: 'P', packages: 1 }])
assert.match(html, /class="measurement-inputs"/)
assert.match(html, /确认本托实测/)
assert.match(html, /长 cm/)
}
})
test('box aggregated pallets render current totals and no manual pallet measurement even after moving', async () => {
const html = await renderMeasurements([{ palletCode: 'NEW', packages: 1, inherited: true, cartonAggregated: true,
grossWeightKg: 3.6, volumeCbm: 0.08, sourceCartonSpecs: [{lengthCm:50,widthCm:40,heightCm:40,grossWeightKg:3.6,cartons:1}] }])
assert.doesNotMatch(html, /移出扣减、移入增加/)
assert.match(html, /0.08 m³ · 3.6 kg/)
assert.doesNotMatch(html, /确认本托实测|重新测量|measurement-inputs/)
})
const mixedBoxes = [
{ cartonMark: 'OTHER', lengthCm: 60, widthCm: 50, heightCm: 50, grossWeightKg: 2.5 },
{ cartonMark: 'SMALL1', customerCartonMark: 'CUSTOMER', lengthCm: 50, widthCm: 40, heightCm: 40, grossWeightKg: 3.6 }
]
test('mixed specs automatically bind the submitted carton without another picker', async () => {
const { value, calls } = setup()
Object.assign(value, { readyToBind: true, requiresMeasuredBoxMapping: true, marks: ['CUSTOMER'], measuredBoxChoices: mixedBoxes,
source: { palletCode: 'OLD', palletVersion: 1 }, target: { palletCode: 'NEW', palletVersion: 1 },
selectedSource: { positionId: '1', positionVersion: 1 }, quantity: '1', loadSources: async () => {}, showBindingMessage() {} })
await value.bind()
assert.deepEqual(calls[0].cartonMarks, ['CUSTOMER'])
assert.deepEqual(calls[0].measuredCartons, [{ cartonMark: 'CUSTOMER', sourceCartonMark: 'SMALL1' }])
assert.doesNotMatch(source, /<picker|chooseMeasuredBox|点击选择实测箱/)
})
test('warehouse carton marks also match automatically and follow the current batch', () => {
const { value } = setup()
Object.assign(value, { requiresMeasuredBoxMapping: true, measuredBoxChoices: mixedBoxes, marks: ['SMALL1'] })
assert.deepEqual(value.measuredCartonBindings(), [{ cartonMark: 'SMALL1', sourceCartonMark: 'SMALL1' }])
value.marks = ['OTHER']
assert.deepEqual(value.measuredCartonBindings(), [{ cartonMark: 'OTHER', sourceCartonMark: 'OTHER' }])
})
test('unmatched, ambiguous or duplicate physical boxes cannot bind another carton', async () => {
for (const [marks, boxes] of [
[['MISSING'], mixedBoxes],
[['CUSTOMER'], [...mixedBoxes, { ...mixedBoxes[0], customerCartonMark: 'CUSTOMER' }]],
[['CUSTOMER', 'SMALL1'], mixedBoxes]
]) {
const { value, calls } = setup()
Object.assign(value, { readyToBind: true, requiresMeasuredBoxMapping: true, measuredBoxChoices: boxes, marks })
await value.bind()
assert.equal(calls.length, 0)
assert.match(value.error, /不匹配/)
}
})
test('entering split quantity prepares the batch and clears invalid quantities', () => {
const { value } = setup()
Object.assign(value, { measuredBoxChoices: [{ cartonMark: 'A' }], eligibleItems: [{ cartonMark: 'X' }],
selectedSource: { movablePackages: 1 }, fillBatch() { this.marks = ['X'] } })
value.prepareMeasuredBatch({ detail: { value: '1' } })
assert.deepEqual(value.marks, ['X'])
value.prepareMeasuredBatch({ detail: { value: '0' } })
assert.deepEqual(value.marks, [])
})