140 lines
5.4 KiB
JavaScript
140 lines
5.4 KiB
JavaScript
#!/usr/bin/env node
|
|||
|
|
|
||
|
|
const assert = require('node:assert/strict');
|
||
|
|
const fs = require('node:fs');
|
||
|
|
const path = require('node:path');
|
||
|
|
|
||
|
|
const root = path.resolve(__dirname, '..');
|
||
|
|
const sourceRoot = path.join(root, 'prototype-src');
|
||
|
|
const general = fs.readFileSync(path.join(sourceRoot, 'modules/10-general.html'), 'utf8');
|
||
|
|
const shell = fs.readFileSync(path.join(sourceRoot, 'shell.html'), 'utf8');
|
||
|
|
const app = fs.readFileSync(path.join(sourceRoot, 'app.js'), 'utf8');
|
||
|
|
const manifest = JSON.parse(fs.readFileSync(path.join(sourceRoot, 'manifest.json'), 'utf8'));
|
||
|
|
|
||
|
|
const generalModule = manifest.modules.find(module => module.file === 'modules/10-general.html');
|
||
|
|
assert.ok(generalModule, 'manifest 中缺少通用资料模块');
|
||
|
|
const genPartnerModuleIndex = generalModule.pages.indexOf('gen-partner-warehouse');
|
||
|
|
assert.ok(genPartnerModuleIndex >= 0, '通用资料模块缺少 gen-partner-warehouse 页面');
|
||
|
|
assert.equal(
|
||
|
|
generalModule.pages[genPartnerModuleIndex + 1],
|
||
|
|
'gen-overseas-quote',
|
||
|
|
'gen-overseas-quote 应紧跟完整仓库页签组登记在通用资料模块中'
|
||
|
|
);
|
||
|
|
|
||
|
|
const genPartnerOrderIndex = manifest.pageOrder.indexOf('gen-partner-warehouse');
|
||
|
|
assert.ok(genPartnerOrderIndex >= 0, '顶层 pageOrder 缺少 gen-partner-warehouse');
|
||
|
|
assert.equal(
|
||
|
|
manifest.pageOrder[genPartnerOrderIndex + 1],
|
||
|
|
'gen-overseas-quote',
|
||
|
|
'gen-overseas-quote 应紧跟完整仓库页签组登记在顶层 pageOrder 中'
|
||
|
|
);
|
||
|
|
|
||
|
|
assert.match(
|
||
|
|
shell,
|
||
|
|
/switchPage\('gen-owned-warehouse',this\)"[^>]*>仓库管理<\/div>\s*<div class="sub-menu-item" onclick="switchPage\('gen-overseas-quote',this\)">海外仓报价<\/div>/,
|
||
|
|
'通用导航中海外仓报价入口必须紧跟仓库管理'
|
||
|
|
);
|
||
|
|
|
||
|
|
assert.equal(
|
||
|
|
(general.match(/id="page-gen-overseas-quote"/g) || []).length,
|
||
|
|
1,
|
||
|
|
'10-general.html 中 page-gen-overseas-quote 必须恰好出现一次'
|
||
|
|
);
|
||
|
|
|
||
|
|
assert.match(
|
||
|
|
general,
|
||
|
|
/#page-gen-overseas-quote \.goq-table\{min-width:1480px;table-layout:fixed;font-size:12px\}/,
|
||
|
|
'海外仓报价列表应为加宽后的操作列保留表格横向空间'
|
||
|
|
);
|
||
|
|
assert.match(
|
||
|
|
general,
|
||
|
|
/#page-gen-overseas-quote \.goq-table th:first-child,#page-gen-overseas-quote \.goq-table td:first-child\{width:250px\}/,
|
||
|
|
'海外仓报价列表操作列宽度应容纳详情、编辑、停用和删除按钮'
|
||
|
|
);
|
||
|
|
|
||
|
|
const quotePageStart = general.indexOf('<div class="page" id="page-gen-overseas-quote">');
|
||
|
|
const quotePageEnd = general.indexOf('<div class="page"', quotePageStart + 1);
|
||
|
|
const quotePage = general.slice(quotePageStart, quotePageEnd < 0 ? general.length : quotePageEnd);
|
||
|
|
for (const field of [
|
||
|
|
'报价名称',
|
||
|
|
'海外仓',
|
||
|
|
'服务商',
|
||
|
|
'币种',
|
||
|
|
'生效日期',
|
||
|
|
'失效日期',
|
||
|
|
'报价版本',
|
||
|
|
'仓储作业费用',
|
||
|
|
'中转派送价格',
|
||
|
|
'目的 FBA 仓',
|
||
|
|
'车型/提货方式',
|
||
|
|
'预估迈数',
|
||
|
|
'最低收费'
|
||
|
|
]) {
|
||
|
|
assert.ok(quotePage.includes(field), `海外仓报价页面缺少字段:${field}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
assert.match(
|
||
|
|
general,
|
||
|
|
/id="modal-gen-overseas-quote-detail"/,
|
||
|
|
'10-general.html 缺少海外仓报价独立详情弹窗'
|
||
|
|
);
|
||
|
|
|
||
|
|
for (const functionName of [
|
||
|
|
'renderOverseasWarehouseQuotes',
|
||
|
|
'resetOverseasWarehouseQuoteFilters',
|
||
|
|
'openOverseasWarehouseQuoteDetail',
|
||
|
|
'renderOverseasWarehouseQuoteDetail',
|
||
|
|
'openOverseasWarehouseQuoteModal',
|
||
|
|
'addOverseasWarehouseFeeRow',
|
||
|
|
'addOverseasTransitPriceRow',
|
||
|
|
'saveOverseasWarehouseQuote',
|
||
|
|
'toggleOverseasWarehouseQuoteStatus',
|
||
|
|
'deleteOverseasWarehouseQuote'
|
||
|
|
]) {
|
||
|
|
assert.match(app, new RegExp(`function\\s+${functionName}\\s*\\(`), `app.js 缺少函数:${functionName}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
function getFunctionSource(functionName) {
|
||
|
|
const start = app.search(new RegExp(`function\\s+${functionName}\\s*\\(`));
|
||
|
|
assert.ok(start >= 0, `app.js 缺少函数:${functionName}`);
|
||
|
|
const sourceFromFunction = app.slice(start);
|
||
|
|
const nextFunctionOffset = sourceFromFunction.slice(1).search(/\nfunction\s+[A-Za-z_$][\w$]*\s*\(/);
|
||
|
|
return nextFunctionOffset < 0
|
||
|
|
? sourceFromFunction
|
||
|
|
: sourceFromFunction.slice(0, nextFunctionOffset + 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
const quoteListSource = getFunctionSource('renderOverseasWarehouseQuotes');
|
||
|
|
const quoteDetailButtonMatch = quoteListSource.match(
|
||
|
|
/<button\b[^>]*\bonclick="openOverseasWarehouseQuoteDetail\([^\"]*\)"[^>]*>\s*详情\s*<\/button>/
|
||
|
|
);
|
||
|
|
const quoteEditButtonMatch = quoteListSource.match(
|
||
|
|
/<button\b[^>]*\bonclick="openOverseasWarehouseQuoteModal\([^\"]*\)"[^>]*>\s*编辑\s*<\/button>/
|
||
|
|
);
|
||
|
|
assert.ok(
|
||
|
|
quoteDetailButtonMatch &&
|
||
|
|
quoteEditButtonMatch &&
|
||
|
|
quoteDetailButtonMatch.index < quoteEditButtonMatch.index,
|
||
|
|
'海外仓报价列表首位缺少“详情”入口'
|
||
|
|
);
|
||
|
|
|
||
|
|
const quoteDetailSource = [
|
||
|
|
getFunctionSource('openOverseasWarehouseQuoteDetail'),
|
||
|
|
getFunctionSource('renderOverseasWarehouseQuoteDetail')
|
||
|
|
].join('\n');
|
||
|
|
assert.match(
|
||
|
|
quoteDetailSource,
|
||
|
|
/openOverseasWarehouseQuoteModal\s*\(/,
|
||
|
|
'海外仓报价详情缺少进入现有编辑弹窗的路径'
|
||
|
|
);
|
||
|
|
|
||
|
|
const quoteDataStart = app.search(/overseasWarehouseQuoteData\s*=\s*\[/);
|
||
|
|
assert.ok(quoteDataStart >= 0, 'app.js 缺少 overseasWarehouseQuoteData 数组');
|
||
|
|
const quoteDataEnd = app.indexOf('];', quoteDataStart);
|
||
|
|
assert.ok(quoteDataEnd > quoteDataStart, 'overseasWarehouseQuoteData 数组缺少结束标记');
|
||
|
|
const quoteDataSource = app.slice(quoteDataStart, quoteDataEnd + 2);
|
||
|
|
assert.match(quoteDataSource, /warehouseFees\s*:/, '报价数据缺少 warehouseFees 字段');
|
||
|
|
assert.match(quoteDataSource, /transitPrices\s*:/, '报价数据缺少 transitPrices 字段');
|
||
|
|
|
||
|
|
console.log('海外仓报价源码契约验证通过。');
|