Files
client-web/src/modules/overseas-warehouse/views/unifiedRelabelTemplate.test.mjs
T
2026-10-28 16:33:35 +08:00

88 lines
6.4 KiB
JavaScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import ts from 'typescript'
const source = readFileSync(new URL('./WarehouseServiceView.vue', import.meta.url), 'utf8')
const csvCell = source.slice(source.indexOf('function csvCell('), source.indexOf('function transferCustomerMarks'))
const buildItems = source.slice(source.indexOf('function buildSkuRelabelItems('), source.indexOf('function addRelabelCargoRow('))
const submitStart = source.indexOf('const sourceInboundOrders =', source.indexOf('async function submit('))
const submitBody = source.slice(submitStart, source.indexOf(' try {', submitStart))
const code = ts.transpileModule(csvCell + buildItems + source.slice(source.indexOf('function relabelTemplateTypeForMode'), source.indexOf('function selectDiscardInbound')) + '\nasync function submitImported() { const idempotencyKey = "test-key"; ' + submitBody + '\nreturn created; }', { compilerOptions: { target: ts.ScriptTarget.ES2022 } }).outputText
function harness(service = 'labeling') {
const state = { props: { service }, cargoRows: { value: [{ id: 1, sku: 'OLD', name: '货物', included: false, cartonMark: 'BOX-1', customerCartonMarks: 'CUSTOMER-1', shipmentNo: '', remark: '' }] }, labelingMode: { value: 'carton' }, importedRelabelBindings: { value: [] }, skuRelabelRows: { value: [] }, transferRelabelRows: { value: [] }, form: { destination: 'ONT8' }, ElMessage: { error: message => errors.push(message), warning: message => errors.push(message), success: () => {} }, createCargoRow: () => ({}), transferCustomerMarks: row => row.customerCartonMarks.split(',') }
const requests = []
Object.assign(state, { isReturnRelabelSource: { value: false }, selectedReturnCandidates: { value: [] }, cartonDetailRows: { get value() { return state.cargoRows.value.filter(row => row.included) } }, createRelabel: async request => { requests.push(request); return { application: { relabelNo: 'TEST-RELABEL' } } } })
Object.assign(state.cargoRows.value[0], { availableQuantity: 1, sourceInventoryBalanceId: '101', sourceInventoryPositionId: '102', sourceInboundOrderId: '103' })
const errors = [], downloads = []
const URL = { createObjectURL: blob => { downloads.push(blob); return 'blob:test' }, revokeObjectURL: () => {} }
const document = { createElement: () => ({ click() {} }) }
const result = new Function(...Object.keys(state), 'URL', 'document', 'let skuRelabelSequence = 0;\n' + code + '\nreturn { downloadRelabelTemplate, importRelabelTemplate, importSelectedBindingsToDetails, buildSkuRelabelItems, submitImported };')(...Object.values(state), URL, document)
async function upload(rows) {
const csv = [['明细行标识', '贴标类型', '仓库唛头', '旧SKU标签', '新SKU标签', '换标数量(件)', '新FBA箱唛', 'FBA货件编号', '备注'], ...rows].map(row => row.join(',')).join('\r\n')
await result.importRelabelTemplate({ target: { files: [new File([csv], '统一模板.csv')], value: 'file' } })
}
return { ...state, ...result, upload, errors, downloads, requests }
}
for (const [type, mode, expected] of [['只换箱唛', 'carton', 'carton'], ['只换 SKU 标签', 'sku', 'sku'], ['SKU 和箱唛都换', 'carton_and_sku', 'mixed']]) {
test(`${type}:统一模板导入并生成对应类型明细`, async () => {
const state = harness()
await state.upload([[1, type, 'BOX-1', 'OLD', mode === 'carton' ? '' : 'NEW', 3, mode === 'sku' ? '' : 'FBA-1', mode === 'sku' ? '' : 'SHIP-1', '']])
assert.deepEqual(state.errors, [])
assert.equal(state.importedRelabelBindings.value[0].templateType, expected)
state.importSelectedBindingsToDetails()
assert.equal(state.labelingMode.value, mode)
if (mode === 'carton') { assert.equal(state.cargoRows.value[0].included, true); assert.equal(state.cargoRows.value[0].quantity, 1) }
else {
assert.equal(state.skuRelabelRows.value[0].newSku, 'NEW')
const [item] = state.buildSkuRelabelItems()
assert.equal(item.operationType, mode === 'sku' ? 'SKU_LABEL' : 'CARTON_AND_SKU')
assert.equal(item.totalPackageCount, 1)
assert.equal(item.skuItems[0].quantity, 3)
assert.equal(item.destinationFbaWarehouseCode, mode === 'sku' ? undefined : 'ONT8')
}
state.form.deliveryMethod = 'TRUCK'
await state.submitImported()
assert.equal(state.requests.length, 1)
assert.equal(state.requests[0].items[0].operationType, mode === 'carton' ? 'CARTON_LABEL' : mode === 'sku' ? 'SKU_LABEL' : 'CARTON_AND_SKU')
assert.equal(state.requests[0].deliveryMethod, mode === 'sku' ? undefined : 'TRUCK')
})
}
test('三种类型下载同一列结构,并带出当前换标类型', async () => {
const state = harness()
const headers = []
for (const mode of ['carton', 'sku', 'carton_and_sku']) {
state.labelingMode.value = mode
state.downloadRelabelTemplate()
const csv = await state.downloads.at(-1).text()
const lines = csv.split('\r\n')
assert.equal(lines.length, 3)
headers.push(lines[0])
assert.match(lines[1], /只换箱唛|只换 SKU 标签|SKU 和箱唛都换/)
}
assert.equal(new Set(headers).size, 1)
})
test('组合换标同箱多 SKU 生成一条箱任务并保留全部 SKU 子项', async () => {
const state = harness()
await state.upload([[1, 'SKU 和箱唛都换', 'BOX-1', 'OLD', 'NEW', 3, 'FBA-1', 'SHIP-1', ''], [1, 'SKU 和箱唛都换', 'BOX-1', 'OLD2', 'NEW2', 2, 'FBA-1', 'SHIP-1', '']])
assert.deepEqual(state.errors, [])
state.importSelectedBindingsToDetails()
await state.submitImported()
assert.equal(state.requests[0].items.length, 1)
assert.equal(state.requests[0].items[0].totalPackageCount, 1)
assert.deepEqual(state.requests[0].items[0].skuItems.map(item => item.quantity), [3, 2])
})
test('混合类型、缺字段、无效数量、重复关系和未知库存均不导入', async () => {
const valid = [1, 'SKU 和箱唛都换', 'BOX-1', 'OLD', 'NEW', 3, 'FBA-1', 'SHIP-1', '']
for (const rows of [[valid, [1, '只换箱唛', 'BOX-2', '', '', 1, 'FBA-2', 'SHIP-2', '']], [[...valid.slice(0, 4), '', ...valid.slice(5)]], [[...valid.slice(0, 5), 0, ...valid.slice(6)]], [valid, valid], [[999, ...valid.slice(1)]], [valid, [1, 'SKU 和箱唛都换', 'BOX-1', 'OTHER', 'NEW2', 1, 'FBA-OTHER', 'SHIP-1', '']]]) {
const state = harness()
await state.upload(rows)
assert.equal(state.errors.length, 1)
assert.equal(state.importedRelabelBindings.value.length, 0)
}
})