94 lines
5.1 KiB
JavaScript
94 lines
5.1 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { readFile } from 'node:fs/promises'
|
|
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')
|
|
const component = new Function('ScanTargetInput', script)({})
|
|
function context() {
|
|
const value = { ...component.data(), $emit() {}, task: { items: [
|
|
{ cartonMark: 'A', relabelledPackages: 1, destinationFbaWarehouseCode: 'ONT8' },
|
|
{ cartonMark: 'B', relabelledPackages: 1, destinationFbaWarehouseCode: 'JFK8' },
|
|
{ cartonMark: 'C', relabelledPackages: 0, destinationFbaWarehouseCode: 'ONT8' },
|
|
{ cartonMark: 'OTHER', relabelledPackages: 1, destinationFbaWarehouseCode: 'ONT8' }
|
|
] } }
|
|
for (const [key, method] of Object.entries(component.methods)) value[key] = method.bind(value)
|
|
for (const [key, method] of Object.entries(component.computed)) Object.defineProperty(value, key, { get: method.bind(value) })
|
|
value.selectSource({ positionId: '1', palletCode: 'SOURCE', movablePackages: 2, cartonMarks: ['A', 'B', 'C'] })
|
|
return value
|
|
}
|
|
test('quantity batch only includes completed boxes from same inbound and destination', () => {
|
|
const value = context()
|
|
value.quantity = '1'; value.fillBatch(); assert.deepEqual(value.marks, ['A'])
|
|
value.quantity = '2'; value.fillBatch(); assert.match(value.error, /不超过/)
|
|
value.quantity = '1.5'; value.fillBatch(); assert.match(value.error, /正整数/)
|
|
value.selectedDestination = 'JFK8'; value.quantity = '1'; value.fillBatch(); assert.deepEqual(value.marks, ['B'])
|
|
})
|
|
|
|
test('submission requires exact count and scanned distinct source and target pallets', () => {
|
|
const value = context(); value.quantity = '1'; value.fillBatch()
|
|
value.source = { palletCode: 'SOURCE' }; value.sourceCode = 'source'
|
|
value.target = { palletCode: 'TARGET' }; value.targetCode = 'TARGET'
|
|
assert.equal(value.readyToBind, true)
|
|
value.toggleMark('A'); assert.equal(value.readyToBind, false)
|
|
value.toggleMark('A'); value.sourceCode = 'OTHER'; assert.equal(value.readyToBind, false)
|
|
value.sourceCode = 'SOURCE'; value.target = { palletCode: 'SOURCE' }; value.targetCode = 'SOURCE'
|
|
assert.equal(value.readyToBind, false)
|
|
})
|
|
test('quantity disassembly has no extra carton scanner', () => {
|
|
assert.doesNotMatch(source, /relabel-move-carton/)
|
|
assert.match(source, /actualSource:/)
|
|
assert.match(source, /仍归属/)
|
|
})
|
|
|
|
test('latest current-round binding is used for rebind source', () => {
|
|
const value = context()
|
|
value.task.history = ['OLD', 'NEW'].map(pallet => ({ action: 'PALLET_BIND', detail: JSON.stringify({ round: 'INITIAL', cartonMarks: ['A'], targetPallets: [pallet] }) }))
|
|
assert.deepEqual(value.currentBindings, [{ mark: 'A', pallet: 'NEW' }])
|
|
value.task.reviewedAt = 'NEW-ROUND'
|
|
assert.deepEqual(value.currentBindings, [{ mark: 'A', pallet: 'NEW' }])
|
|
value.task.history.push({ action: 'REWORK_ARCHIVE', detail: '{}' })
|
|
assert.deepEqual(value.currentBindings, [])
|
|
})
|
|
|
|
test('rescan same bound pallet does not call stock movement', async () => {
|
|
const value = context(); value.rebindSelection = { mark: 'A', pallet: 'TARGET' }; value.targetCode = 'target'
|
|
let message = ''
|
|
value.showBindingMessage = (title, content) => { message = content }
|
|
value.run = async () => assert.fail('same pallet must not move stock')
|
|
await value.submitRebind()
|
|
assert.match(message, /不会重复扣库存/)
|
|
})
|
|
|
|
test('target confirmation submits binding directly, with no second submit button', async () => {
|
|
const value = context(); value.quantity = '1'; value.fillBatch()
|
|
value.source = { palletCode: 'SOURCE' }; value.sourceCode = 'SOURCE'; value.targetCode = 'TARGET'
|
|
let binds = 0
|
|
value.resolve = async kind => { assert.equal(kind, 'target'); value.target = { palletCode: 'TARGET' } }
|
|
value.bind = async () => { binds++ }
|
|
await value.confirmTargetAndBind()
|
|
assert.equal(binds, 1)
|
|
assert.match(source, /@tap="confirmTargetAndBind"/)
|
|
assert.doesNotMatch(source, /@tap="bind"/)
|
|
})
|
|
|
|
test('missing source scan shows modal and never submits a binding', async () => {
|
|
const value = context(); value.quantity = '1'; value.fillBatch(); value.targetCode = 'TARGET'
|
|
let message = ''
|
|
value.showBindingMessage = (title, content) => { message = content }
|
|
value.bind = async () => assert.fail('must not bind without source confirmation')
|
|
value.resolve = async () => assert.fail('must validate source first')
|
|
await value.confirmTargetAndBind()
|
|
assert.match(message, /扫描并确认实际来源托盘/)
|
|
})
|
|
|
|
test('target lookup failure cannot submit binding or report success', async () => {
|
|
const value = context(); value.quantity = '1'; value.fillBatch()
|
|
value.source = { palletCode: 'SOURCE' }; value.sourceCode = 'SOURCE'; value.targetCode = 'TARGET'
|
|
value.resolve = async () => { value.error = '目标托盘不可用' }
|
|
let title = ''
|
|
value.showBindingMessage = heading => { title = heading }
|
|
value.bind = async () => assert.fail('must not bind after lookup failure')
|
|
await value.confirmTargetAndBind()
|
|
assert.equal(title, '绑定失败')
|
|
})
|