Files
docs/悦/官网头程下单/tests/return-relabel-sku-logistics.test.js
T
2026-09-08 18:17:00 +08:00

139 lines
5.8 KiB
JavaScript

const assert = require('node:assert/strict');
const fs = require('node:fs');
const vm = require('node:vm');
const html = fs.readFileSync('workbench.html', 'utf8');
function extractFunction(name) {
const start = html.indexOf(`function ${name}(`);
assert.notEqual(start, -1, `${name} should exist`);
const bodyStart = html.indexOf('{', start);
let depth = 0;
for (let index = bodyStart; index < html.length; index += 1) {
if (html[index] === '{') depth += 1;
if (html[index] === '}') depth -= 1;
if (depth === 0) return html.slice(start, index + 1);
}
throw new Error(`Unable to extract ${name}`);
}
// Regression caught: logistics fields drift back to order-level controls or
// appear after the SKU instead of being the first two cargo columns.
const createPage = html.match(/<div class="page-content" id="page-return-relabel-create">([\s\S]*?)<div class="page-content" id="page-return-relabel-detail">/)?.[1] || '';
const returnInfo = createPage.match(/<div class="return-relabel-section-title">退货信息<\/div>([\s\S]*?)<div class="card return-relabel-section">/)?.[1] || '';
const cargoHeader = createPage.match(/id="return-relabel-sku-table">\s*<thead><tr>([\s\S]*?)<\/tr><\/thead>/)?.[1] || '';
assert.ok(returnInfo, '退货信息区域 should exist');
assert.doesNotMatch(returnInfo, /name="(?:carrier|trackingNo)"/, '物流字段不应再作为整单输入');
assert.match(
cargoHeader,
/^<th>承运商[\s\S]*?<th>运单号[\s\S]*?<th>商品SKU/,
'承运商、运单号应为商品 SKU 前两列'
);
// Carrier/tracking controls remain available on each SKU row but are optional.
const appendedRows = [];
const rowContext = {
document: {
getElementById: id => id === 'return-relabel-sku-body' ? { appendChild: row => appendedRows.push(row) } : null,
createElement: () => ({ innerHTML: '' })
},
escapeReturnRelabelHtml: value => String(value == null ? '' : value)
};
const addReturnRelabelSkuRow = vm.runInNewContext(
`(${extractFunction('addReturnRelabelSkuRow')})`,
rowContext
);
addReturnRelabelSkuRow({ carrier: 'UPS', trackingNo: '1Z-001', sku: 'SKU-1' });
assert.match(
appendedRows[0].innerHTML,
/^<td><input[^>]*return-relabel-carrier[^>]*value="UPS"[^>]*><\/td><td><input[^>]*return-relabel-tracking-no[^>]*value="1Z-001"[^>]*><\/td><td><input[^>]*return-relabel-sku/,
'每条 SKU 行都应先生成可选的承运商和运单号输入框'
);
assert.doesNotMatch(appendedRows[0].innerHTML, /return-relabel-carrier[^>]*required/, '承运商不应设置 required');
assert.doesNotMatch(appendedRows[0].innerHTML, /return-relabel-tracking-no[^>]*required/, '运单号不应设置 required');
function control(value, extra = {}) {
return { value, ...extra };
}
function cargoRow(values) {
const fields = {
'.return-relabel-carrier': control(values.carrier),
'.return-relabel-tracking-no': control(values.trackingNo),
'.return-relabel-sku': control(values.sku),
'.return-relabel-name': control(values.name),
'.return-relabel-fnsku': control(values.fnsku),
'.return-relabel-new-sku': control(values.newSku || ''),
'.return-relabel-quantity': control(String(values.quantity))
};
return { querySelector: selector => fields[selector] || null };
}
const rows = [
cargoRow({ carrier: 'UPS', trackingNo: '1Z-001', sku: 'SKU-1', name: '商品一', fnsku: 'FN-1', quantity: 2 }),
cargoRow({ carrier: 'FedEx', trackingNo: 'FX-002', sku: 'SKU-2', name: '商品二', fnsku: 'FN-2', quantity: 3 })
];
const error = { textContent: '' };
const submitButton = { disabled: false };
const form = {
checkValidity: () => true,
reportValidity() {},
elements: {
inboundCode: control('IN-001'),
sourceFba: control('ONT8'),
reason: control('客户退货'),
receivingWarehouse: control('洛杉矶仓'),
destinationFba: control('LAX9'),
relabel: control('', { checked: false }),
labelCase: control('Case1'),
cartonLabel: control('', { files: [] }),
skuLabel: control('', { files: [] }),
address: control('123 Main St'),
expectedArrival: control('2026-09-10T10:00'),
returnRemark: control(''),
tailRemark: control('')
}
};
const saved = [];
const runtime = {
document: {
getElementById: id => ({
'return-relabel-form': form,
'return-relabel-error': error,
'return-relabel-submit': submitButton
}[id] || null),
querySelectorAll: selector => selector === '#return-relabel-sku-body tr' ? rows : []
},
loadReturnRelabelOrders: () => [],
saveReturnRelabelOrders: orders => { saved.push(orders); return true; },
renderReturnRelabelList() {},
showToast() {},
openReturnRelabelList() {},
returnRelabelFilteredOrders: null,
returnRelabelSubmitting: false
};
vm.runInNewContext(
`${extractFunction('validateReturnRelabelForm')}
${extractFunction('summarizeReturnRelabelSkuField')}
${extractFunction('submitReturnRelabelOrder')}`,
runtime
);
// Optional logistics fields must not block a later SKU from submitting.
rows[1].querySelector('.return-relabel-tracking-no').value = '';
assert.equal(runtime.validateReturnRelabelForm(), true);
assert.equal(error.textContent, '');
rows[1].querySelector('.return-relabel-tracking-no').value = 'FX-002';
// Regression caught: only the first row's logistics data is persisted.
assert.equal(runtime.submitReturnRelabelOrder({ preventDefault() {} }), false);
const order = saved[0][0];
assert.deepEqual(JSON.parse(JSON.stringify(order.skus)), [
{ carrier: 'UPS', trackingNo: '1Z-001', sku: 'SKU-1', name: '商品一', fnsku: 'FN-1', newSku: '', quantity: 2 },
{ carrier: 'FedEx', trackingNo: 'FX-002', sku: 'SKU-2', name: '商品二', fnsku: 'FN-2', newSku: '', quantity: 3 }
]);
assert.equal(order.carrier, 'UPS、FedEx', '整单兼容字段应汇总去重后的承运商');
assert.equal(order.trackingNo, '1Z-001、FX-002', '整单兼容字段应汇总去重后的运单号');
console.log('return relabel SKU logistics: ok');