96 lines
4.2 KiB
JavaScript
96 lines
4.2 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const htmlPath = path.resolve(__dirname, '..', 'index.html');
|
|
const html = fs.readFileSync(htmlPath, 'utf8');
|
|
|
|
function expect(pattern, message) {
|
|
if (!pattern.test(html)) throw new Error(message);
|
|
}
|
|
|
|
function expectIn(source, pattern, message) {
|
|
if (!pattern.test(source)) throw new Error(message);
|
|
}
|
|
|
|
function extractPageFragment(startId, endId) {
|
|
const start = html.indexOf(`id="${startId}"`);
|
|
const end = html.indexOf(`id="${endId}"`, start);
|
|
if (start === -1 || end === -1 || end <= start) {
|
|
throw new Error(`无法提取页面片段:${startId} 至 ${endId}`);
|
|
}
|
|
return html.slice(start, end);
|
|
}
|
|
|
|
function extractFunctionSource(name) {
|
|
const signature = `function ${name}(`;
|
|
const start = html.indexOf(signature);
|
|
if (start === -1) throw new Error(`无法提取函数源码:${name}`);
|
|
|
|
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(`函数源码未闭合:${name}`);
|
|
}
|
|
|
|
const warehouseStockDetailPage = extractPageFragment(
|
|
'page-warehouse-stock-detail',
|
|
'page-inventory-transactions'
|
|
);
|
|
const renderWarehouseStockDetailSource = extractFunctionSource('renderWarehouseStockDetail');
|
|
|
|
expect(/id="page-fba-stock-management"/, '应保留海外仓库存管理入口');
|
|
expect(/id="wms-inventory-summary"/, '应显示 WMS 库存汇总');
|
|
if (/data-stock-tab="(?:inventory-overview|warehouse-stock|fba-return-stock|overseas-stock|purchase-stock)"/.test(html)) {
|
|
throw new Error('海外仓库存管理不应继续显示旧业务页签');
|
|
}
|
|
|
|
[
|
|
'page-inventory-overview',
|
|
'inventory-overview-owner',
|
|
'inventory-overview-sku',
|
|
'inventory-overview-name',
|
|
'inventory-overview-wh',
|
|
'tbody-inventory-overview',
|
|
'inventory-overview-total',
|
|
'page-warehouse-stock-detail',
|
|
'tbody-warehouse-stock-detail-ledger'
|
|
].forEach(id => expect(new RegExp(`id="${id}"`), `缺少页面元素 ${id}`));
|
|
|
|
['在库总量', '可用库存', '锁定库存', '暂扣库存', '采购库存', '进销存单据明细'].forEach(label => {
|
|
expect(new RegExp(label), `缺少字段或模块:${label}`);
|
|
});
|
|
|
|
[
|
|
'buildUnifiedInventoryData',
|
|
'renderUnifiedInventory',
|
|
'unifiedInventorySearch',
|
|
'unifiedInventoryReset',
|
|
'getUnifiedInventoryDocuments',
|
|
'openWarehouseStockDetail',
|
|
'renderWarehouseStockDetail',
|
|
'backToWarehouseStock'
|
|
].forEach(name => expect(new RegExp(`function\\s+${name}\\s*\\(`), `缺少函数 ${name}`));
|
|
|
|
expect(/JSON\.stringify\(\[owner,warehouse,sku\]\)/, '统一库存必须按无歧义的客户 + 海外仓 + SKU 聚合');
|
|
expect(/openWarehouseStockDetail\(/, '总览列表应提供详情入口');
|
|
expect(/if\(page==='fba-stock-management'\)\s*\{\s*renderUnifiedInventory\(\)/, '进入库存管理时应直接渲染 WMS 工作台');
|
|
expect(/function\s+buildInventoryTransactionData\(/, '应构建独立进销存记录');
|
|
expect(/row\.owner===record\.owner&&row\.warehouse===record\.warehouse&&row\.sku===record\.sku/, '详情流水应按客户、仓库、SKU过滤');
|
|
|
|
expectIn(warehouseStockDetailPage, /<div class="psd-ledger-title">\s*库位库存\s*<\/div>/, '库存详情模块标题必须为“库位库存”');
|
|
if (/批次号|批次与库位库存/.test(warehouseStockDetailPage)) {
|
|
throw new Error('库存详情页面片段不得包含“批次号”或“批次与库位库存”');
|
|
}
|
|
if (/row\.batchNo/.test(renderWarehouseStockDetailSource)) {
|
|
throw new Error('库存详情渲染函数不得包含 row.batchNo');
|
|
}
|
|
expectIn(warehouseStockDetailPage, /id="tbody-wms-detail-batches"[^>]*>\s*<tr>\s*<td\s+colspan="8"/s, 'tbody-wms-detail-batches 空状态必须占 8 列');
|
|
expectIn(warehouseStockDetailPage, /id="tbody-wms-detail-pallets"[^>]*>\s*<tr>\s*<td\s+colspan="5"/s, 'tbody-wms-detail-pallets 空状态必须占 5 列');
|
|
expectIn(warehouseStockDetailPage, /id="tbody-warehouse-stock-detail-ledger"[^>]*>\s*<tr>\s*<td\s+colspan="11"/s, 'tbody-warehouse-stock-detail-ledger 空状态必须占 11 列');
|
|
|
|
console.log('PASS: unified overseas inventory overview and detail contract verified');
|