175 lines
7.1 KiB
JavaScript
175 lines
7.1 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const vm = require('node:vm');
|
|
|
|
const root = path.resolve(__dirname, '..');
|
|
const sourceRoot = path.join(root, 'prototype-src');
|
|
const manifest = JSON.parse(fs.readFileSync(path.join(sourceRoot, 'manifest.json'), 'utf8'));
|
|
const general = fs.readFileSync(path.join(sourceRoot, 'modules/10-general.html'), 'utf8');
|
|
const app = fs.readFileSync(path.join(sourceRoot, 'app.js'), 'utf8');
|
|
const shell = fs.readFileSync(path.join(sourceRoot, 'shell.html'), 'utf8');
|
|
|
|
function extractFunction(source, name) {
|
|
const start = source.indexOf(`function ${name}(`);
|
|
assert.notEqual(start, -1, `缺少 ${name} 函数`);
|
|
const bodyStart = source.indexOf('{', start);
|
|
let depth = 0;
|
|
let quote = '';
|
|
let escaped = false;
|
|
for (let index = bodyStart; index < source.length; index += 1) {
|
|
const char = source[index];
|
|
if (quote) {
|
|
if (escaped) escaped = false;
|
|
else if (char === '\\') escaped = true;
|
|
else if (char === quote) quote = '';
|
|
continue;
|
|
}
|
|
if (char === "'" || char === '"' || char === '`') {
|
|
quote = char;
|
|
continue;
|
|
}
|
|
if (char === '{') depth += 1;
|
|
if (char === '}') {
|
|
depth -= 1;
|
|
if (depth === 0) return source.slice(start, index + 1);
|
|
}
|
|
}
|
|
throw new Error(`${name} 函数未正确闭合`);
|
|
}
|
|
|
|
const generalModule = manifest.modules.find(item => item.file === 'modules/10-general.html');
|
|
assert.ok(generalModule, 'manifest 缺少通用资料模块');
|
|
assert.equal(
|
|
manifest.pageOrder.filter(id => id === 'vehicle-detail').length,
|
|
1,
|
|
'pageOrder 应唯一登记 vehicle-detail',
|
|
);
|
|
assert.equal(
|
|
generalModule.pages.filter(id => id === 'vehicle-detail').length,
|
|
1,
|
|
'通用资料模块应唯一登记 vehicle-detail',
|
|
);
|
|
|
|
const vehicleListStart = general.indexOf('<div class="page" id="page-vehicle">');
|
|
const vehicleDetailStart = general.indexOf('<div class="page" id="page-vehicle-detail">');
|
|
assert.notEqual(vehicleListStart, -1, '缺少车辆列表页面');
|
|
assert.notEqual(vehicleDetailStart, -1, '缺少独立车辆详情页面');
|
|
const vehicleListPage = general.slice(vehicleListStart, vehicleDetailStart);
|
|
const vehicleDetailEnd = general.indexOf('<div class="page"', vehicleDetailStart + 1);
|
|
const vehicleDetailPage = general.slice(
|
|
vehicleDetailStart,
|
|
vehicleDetailEnd === -1 ? general.length : vehicleDetailEnd,
|
|
);
|
|
|
|
assert.match(
|
|
vehicleListPage,
|
|
/class="vehicle-region-tab active"[^>]*data-region="domestic"/,
|
|
'缺少默认选中的国内车辆一级标签',
|
|
);
|
|
assert.match(
|
|
vehicleListPage,
|
|
/class="vehicle-region-tab"[^>]*data-region="overseas"/,
|
|
'缺少海外车辆一级标签',
|
|
);
|
|
assert.match(
|
|
vehicleListPage,
|
|
/class="vehicle-owner-tab active"[^>]*data-owner="own"/,
|
|
'缺少默认选中的自有车辆二级标签',
|
|
);
|
|
assert.match(
|
|
vehicleListPage,
|
|
/class="vehicle-owner-tab"[^>]*data-owner="dispatch"/,
|
|
'缺少外派车辆二级标签',
|
|
);
|
|
assert.doesNotMatch(vehicleListPage, /vregion-pill/, '车辆列表仍保留旧区域胶囊筛选');
|
|
assert.doesNotMatch(vehicleListPage, />国外</, '车辆列表仍使用“国外”文案');
|
|
assert.match(
|
|
vehicleListPage,
|
|
/<div class="breadcrumb">首页 <span class="sep">><\/span> 通用/,
|
|
'车辆列表面包屑应归属通用模块',
|
|
);
|
|
assert.equal(
|
|
(vehicleListPage.match(/class="vehicle-overseas-only"[^>]*>邮箱<\/th>/g) || []).length,
|
|
2,
|
|
'自有和外派车辆列表都应提供海外专属邮箱列',
|
|
);
|
|
assert.match(
|
|
vehicleListPage,
|
|
/class="vehicle-overseas-only" style="display:none;/,
|
|
'国内车辆默认视图应隐藏邮箱列',
|
|
);
|
|
assert.match(vehicleListPage, /id="vehicle-m-email"/, '车辆新增/编辑表单缺少邮箱字段');
|
|
assert.match(
|
|
vehicleListPage,
|
|
/id="vehicle-m-region"[^>]*onchange="syncVehicleEmailFieldVisibility\(\)"/,
|
|
'切换车辆区域时应同步邮箱字段可见性',
|
|
);
|
|
|
|
assert.match(vehicleDetailPage, /id="vehicle-detail-plate"/, '详情页缺少车牌标题节点');
|
|
assert.match(vehicleDetailPage, /id="vehicle-detail-status"/, '详情页缺少状态节点');
|
|
assert.match(vehicleDetailPage, /id="vehicle-detail-info"/, '详情页缺少车辆信息区域');
|
|
assert.match(app, /\['邮箱',vehicle\.email\|\|'—'\]/, '车辆详情缺少邮箱字段');
|
|
assert.match(vehicleDetailPage, /id="vehicle-detail-orders-body"/, '详情页缺少派送订单明细表体');
|
|
assert.match(vehicleDetailPage, /id="vehicle-detail-history-body"/, '详情页缺少派送更换记录表体');
|
|
assert.match(vehicleDetailPage, /onclick="backToVehicleList\(\)"/, '详情页缺少返回列表入口');
|
|
assert.doesNotMatch(general, /id="modal-vehicle-view"/, '车辆查看弹窗尚未移除');
|
|
|
|
assert.match(app, /function\s+switchVehicleRegion\s*\(/, '缺少区域标签切换函数');
|
|
assert.match(app, /function\s+openVehicleDetail\s*\(/, '缺少进入车辆详情函数');
|
|
assert.match(app, /function\s+renderVehicleDetail\s*\(/, '缺少车辆详情渲染函数');
|
|
assert.match(app, /function\s+backToVehicleList\s*\(/, '缺少返回车辆列表函数');
|
|
assert.doesNotMatch(app, /showModal\(['"]modal-vehicle-view['"]\)/, '查看车辆仍会打开弹窗');
|
|
assert.match(shell, /\.vehicle-detail-grid/, '缺少车辆详情信息栅格样式');
|
|
assert.match(shell, /@media[^}]*max-width:\s*900px/s, '缺少车辆详情窄屏适配');
|
|
|
|
const aggregateSource = extractFunction(app, 'getVehicleDispatchOrders');
|
|
const emailVisibilitySource = extractFunction(app, 'syncVehicleEmailFieldVisibility');
|
|
const detailRenderSource = extractFunction(app, 'renderVehicleDetail');
|
|
const openDetailSource = extractFunction(app, 'openVehicleDetail');
|
|
const backToListSource = extractFunction(app, 'backToVehicleList');
|
|
assert.doesNotMatch(detailRenderSource, /\bd\./, '详情渲染仍引用旧弹窗局部变量 d');
|
|
assert.match(emailVisibilitySource, /region==='overseas'/, '邮箱表单应仅对海外车辆显示');
|
|
assert.match(app, /const email=region==='overseas'/, '保存车辆时应仅为海外车辆读取邮箱');
|
|
assert.match(
|
|
openDetailSource,
|
|
/switchPage\('vehicle-detail',vehicleNav\)/,
|
|
'进入详情页后应保留车辆列表导航高亮',
|
|
);
|
|
assert.match(
|
|
backToListSource,
|
|
/switchPage\('vehicle',vehicleNav\)/,
|
|
'返回列表后应恢复车辆列表导航高亮',
|
|
);
|
|
const runtime = {Array, Map, Set, String};
|
|
vm.createContext(runtime);
|
|
vm.runInContext(`${aggregateSource};this.getVehicleDispatchOrders=getVehicleDispatchOrders;`, runtime);
|
|
|
|
const result = runtime.getVehicleDispatchOrders(
|
|
{
|
|
id: 'VD1',
|
|
fleetChangeHistory: [
|
|
{dispatchNo: 'DSP-OLD'},
|
|
{dispatchNo: 'DSP-CURRENT'},
|
|
],
|
|
},
|
|
[
|
|
{dispatchNo: 'DSP-OLD', fleetVehicleId: 'VD2'},
|
|
{dispatchNo: 'DSP-CURRENT', fleetVehicleId: 'VD1'},
|
|
{dispatchNo: 'DSP-CURRENT', fleetVehicleId: 'VD1'},
|
|
{dispatchNo: 'DSP-OTHER', fleetVehicleId: 'VD3'},
|
|
],
|
|
);
|
|
assert.deepEqual(
|
|
JSON.parse(JSON.stringify(result.map(item => [item.record.dispatchNo, item.relation]))),
|
|
[
|
|
['DSP-OLD', '历史关联'],
|
|
['DSP-CURRENT', '当前关联'],
|
|
],
|
|
'车辆派送订单应合并当前与历史关联、去重并优先标记当前关联',
|
|
);
|
|
|
|
console.log('VEHICLE_REGION_TABS_DETAIL_CHECK_PASS');
|