import assert from 'node:assert/strict'; import { existsSync, readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import path from 'node:path'; import { test } from 'node:test'; const prototypePath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '官网头程下单', 'workbench.html'); const html = existsSync(prototypePath) ? readFileSync(prototypePath, 'utf8') : ''; function fn(name) { const start = html.indexOf(`function ${name}(`); assert.ok(start >= 0, `${name} should exist`); const next = html.indexOf('\n function ', start + 1); return html.slice(start, next >= 0 ? next : html.length); } test('sea order navigation exposes only three business entry points', () => { const group = html.match(/([\s\S]*?)/); assert.ok(group, 'sea order menu should exist'); assert.equal((group[1].match(/data-sea-action=/g) || []).length, 0); const entries = [...group[1].matchAll(/data-business="(Procurement|Truck|Pallet)"[^>]*onclick="([^"]+)"/g)]; assert.equal(entries.length, 3); for (const [type, label] of [['Procurement', '海外采购'], ['Truck', '美国本土卡'], ['Pallet', '美本土散板']]) { const entry = entries.find(([, , onclick]) => onclick.includes(`openSeaBusiness('${type}','list'`)); assert.ok(entry, `${label} navigation entry should open its list page`); assert.match(entry[0], new RegExp(`data-business="${type}"`)); } }); test('three sea business list pages include add, query, and order lists', () => { const cases = [ ['sea-procurement-page', 'Procurement', '海外采购', ['订单号', '采购品类', '商品规格', '采购数量', '预算单价', '状态', '操作']], ['sea-truck-page', 'Truck', '美国本土卡', ['操作', '订单编号', '运输类型', '起运地', '目的地', '柜型', '总重量(kg)', '预算总价', '要求时间', '状态']], ['sea-pallet-page', 'Pallet', '美本土散板', ['操作', '订单编号', '运输方式', '是否打盘', '运输类型', '起运地', '目的地', '总重量(kg)', '预算总价', '要求时间', '状态']], ]; for (const [id, type, label, headers] of cases) { const start = html.indexOf(`id="${id}"`); assert.ok(start >= 0, `${id} should exist`); const page = html.slice(start, html.indexOf('', start) + 10); assert.match(page, new RegExp(label)); assert.match(page, new RegExp(`openSeaBusiness\\('${type}','new'`)); assert.match(page, new RegExp(`querySeaOrders\\('${type}'\\)`)); assert.match(page, new RegExp(`resetSeaOrders\\('${type}'\\)`)); for (const header of headers) assert.match(page, new RegExp(`${header.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`)); } const truckStart = html.indexOf('id="sea-truck-page"'); const truckPage = html.slice(truckStart, html.indexOf('', truckStart) + 10); assert.doesNotMatch(truckPage, /联系人<\/th>|联系方式<\/th>/); assert.match(html.slice(html.indexOf('data-order-form="Truck"'), html.indexOf('', html.indexOf('data-order-form="Truck"'))), /name="预算总价"/); const palletStart = html.indexOf('id="sea-pallet-page"'); const palletPage = html.slice(palletStart, html.indexOf('', palletStart) + 10); assert.doesNotMatch(palletPage, /联系人<\/th>|联系方式<\/th>/); assert.match(html.slice(html.indexOf('data-order-form="Pallet"'), html.indexOf('', html.indexOf('data-order-form="Pallet"'))), /name="预算总价"/); }); test('all sea business orders support edit and detail actions', () => { for (const name of ['openSeaOrderEditor', 'closeSeaOrderEditor', 'saveSeaOrderEdit', 'showSeaOrderDetail']) fn(name); assert.match(fn('renderSeaOrders'), /openSeaOrderEditor/); assert.match(fn('renderSeaOrders'), /showSeaOrderDetail/); assert.match(html, /id="sea-order-edit-modal"/); assert.match(html, /id="sea-order-edit-form"/); assert.match(fn('openSeaOrderEditor'), /data-order-form/); assert.match(fn('saveSeaOrderEdit'), /seaOrders\[type\]/); }); test('sea business details expose business, carrier, and progress information', () => { const details = [ ['sea-procurement-detail', ['商品信息', '订单信息', '快递信息']], ['sea-truck-detail', ['运输信息', '货物信息', '承运商信息', '运输进度']], ['sea-pallet-detail', ['运输信息', '货物信息', '承运商信息', '运输进度']], ]; for (const [id, sections] of details) { const start = html.indexOf(`id="${id}"`); assert.ok(start >= 0, `${id} should exist`); const detail = html.slice(start, html.indexOf('', start) + 10); for (const section of sections) assert.match(detail, new RegExp(section)); assert.match(detail, /data-detail-content/); } const procurementDetail = html.slice(html.indexOf('id="sea-procurement-detail"'), html.indexOf('', html.indexOf('id="sea-procurement-detail"')) + 10); assert.doesNotMatch(procurementDetail, /采购进度/); assert.doesNotMatch(procurementDetail, /承运商信息/); assert.match(procurementDetail, /data-detail-content="预算总价"/); for (const field of ['订单号', '采购数量', '预算单价', '订单状态', '联系人', '联系电话', '收货地址', '订单备注']) { assert.match(procurementDetail, new RegExp(field)); } for (const field of ['国内快递公司', '国内运单号', '海外快递公司', '海外运单号']) { assert.match(procurementDetail, new RegExp(`data-detail-content="${field}"`)); } }); test('sea business routing reuses existing forms and isolates order state', () => { for (const name of ['showSeaBusinessPage', 'showSeaBusinessOrderForm', 'openSeaBusiness', 'renderSeaOrders', 'querySeaOrders', 'resetSeaOrders']) fn(name); assert.match(html, /const\s+seaOrders\s*=\s*\{\s*Procurement:\s*\[/); assert.match(html, /data-order-form="Procurement"/); assert.match(html, /data-order-form="Truck"/); assert.match(html, /data-order-form="Pallet"/); assert.doesNotMatch(fn('openSeaBusiness'), /data-sea-action/); assert.match(fn('openSeaBusiness'), /dash-nav-link\[data-business=/); assert.match(fn('openOrder'), /openSeaBusiness\(type,'new'/); assert.match(fn('querySeaOrders'), /seaOrders\[type\]/); assert.match(html, /function\s+collectSeaOrderFields\s*\(/); }); test('sea business controls match overseas warehouse colors', () => { const styleStart = html.indexOf('.sea-business-page'); const styleEnd = html.indexOf('', styleStart); const styles = html.slice(styleStart, styleEnd); assert.match(styles, /\.sea-business-page[^{}]*\.btn-primary|\.sea-business-form-panel[^{}]*\.btn-primary/); assert.match(styles, /#667eea/); assert.match(styles, /#764ba2/); assert.match(styles, /\.sea-business-page \.sea-order-table th/); assert.match(styles, /color:\s*#667eea/); });