138 lines
5.2 KiB
JavaScript
138 lines
5.2 KiB
JavaScript
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 shell = fs.readFileSync(path.join(sourceRoot, 'shell.html'), 'utf8');
|
|
const manifest = JSON.parse(fs.readFileSync(path.join(sourceRoot, 'manifest.json'), 'utf8'));
|
|
const overseasDelivery = fs.readFileSync(
|
|
path.join(sourceRoot, 'modules/04-overseas-delivery.html'),
|
|
'utf8',
|
|
);
|
|
const customerServicePath = path.join(sourceRoot, 'modules/04a-customer-service.html');
|
|
const customerService = fs.existsSync(customerServicePath)
|
|
? fs.readFileSync(customerServicePath, 'utf8')
|
|
: '';
|
|
const app = fs.readFileSync(path.join(sourceRoot, 'app.js'), 'utf8');
|
|
|
|
function sidebarItemStart(source, marker) {
|
|
const markerIndex = source.indexOf(marker);
|
|
return markerIndex < 0 ? -1 : source.lastIndexOf('<div class="sidebar-item"', markerIndex);
|
|
}
|
|
|
|
function sidebarItemAt(source, start) {
|
|
if (start < 0) return '';
|
|
const nextStart = source.indexOf('<div class="sidebar-item"', start + 1);
|
|
return source.slice(start, nextStart < 0 ? source.length : nextStart);
|
|
}
|
|
|
|
function sidebarItemStartByLabel(source, label) {
|
|
const starts = [...source.matchAll(/<div class="sidebar-item"(?:\s[^>]*)?>/g)].map(
|
|
match => match.index,
|
|
);
|
|
return starts.find((start, index) => {
|
|
const item = source.slice(start, starts[index + 1] ?? source.length);
|
|
const labelEnd = item.indexOf('</div>');
|
|
return labelEnd >= 0 && item.slice(0, labelEnd).includes(label);
|
|
}) ?? -1;
|
|
}
|
|
|
|
function countMatches(source, pattern) {
|
|
return [...source.matchAll(pattern)].length;
|
|
}
|
|
|
|
function pageSource(source, pageId) {
|
|
const pagePattern = new RegExp(`<div\\b[^>]*\\bid=(["'])page-${pageId}\\1[^>]*>`);
|
|
const match = pagePattern.exec(source);
|
|
if (!match) return '';
|
|
const nextPagePattern = /<div\b[^>]*\bid=["']page-/g;
|
|
nextPagePattern.lastIndex = match.index + match[0].length;
|
|
const nextPage = nextPagePattern.exec(source);
|
|
return source.slice(match.index, nextPage ? nextPage.index : source.length);
|
|
}
|
|
|
|
const outboundNavStart = sidebarItemStart(shell, 'data-menu="outbound"');
|
|
const supplierNavStart = sidebarItemStart(shell, 'data-menu="supplier"');
|
|
const customerServiceNavStart = sidebarItemStartByLabel(shell, '客户服务');
|
|
|
|
assert.ok(customerServiceNavStart >= 0, '侧栏缺少客户服务导航');
|
|
assert.ok(outboundNavStart >= 0, '侧栏缺少海外派送导航');
|
|
assert.ok(supplierNavStart >= 0, '侧栏缺少供应商中心导航');
|
|
assert.ok(
|
|
outboundNavStart < customerServiceNavStart && customerServiceNavStart < supplierNavStart,
|
|
'客户服务导航必须位于海外派送之后、供应商中心之前',
|
|
);
|
|
|
|
const outboundNav = sidebarItemAt(shell, outboundNavStart);
|
|
const customerServiceNav = sidebarItemAt(shell, customerServiceNavStart);
|
|
|
|
assert.doesNotMatch(
|
|
outboundNav,
|
|
/outbound-exception|异常订单/,
|
|
'海外派送导航不应再包含异常订单',
|
|
);
|
|
assert.match(
|
|
customerServiceNav,
|
|
/switchPage\(\s*['"]outbound-exception['"]\s*,\s*this\s*\)/,
|
|
'客户服务导航缺少 outbound-exception 入口',
|
|
);
|
|
assert.match(customerServiceNav, />\s*异常订单\s*</, '客户服务导航缺少异常订单文案');
|
|
|
|
const overseasDeliveryIndex = manifest.modules.findIndex(
|
|
item => item.file === 'modules/04-overseas-delivery.html',
|
|
);
|
|
const customerServiceIndex = manifest.modules.findIndex(
|
|
item => item.file === 'modules/04a-customer-service.html',
|
|
);
|
|
const customerServiceModule = manifest.modules[customerServiceIndex];
|
|
|
|
assert.ok(overseasDeliveryIndex >= 0, 'manifest 缺少海外派送模块');
|
|
assert.ok(customerServiceIndex >= 0, 'manifest 缺少客户服务模块');
|
|
assert.equal(customerServiceModule.title, '客户服务', '客户服务模块标题不正确');
|
|
assert.equal(
|
|
customerServiceIndex,
|
|
overseasDeliveryIndex + 1,
|
|
'客户服务模块必须紧邻海外派送之后',
|
|
);
|
|
assert.ok(
|
|
customerServiceModule.pages.includes('outbound-exception'),
|
|
'客户服务模块必须归属 outbound-exception 页面',
|
|
);
|
|
assert.ok(
|
|
!manifest.modules[overseasDeliveryIndex].pages.includes('outbound-exception'),
|
|
'海外派送模块不应再归属 outbound-exception 页面',
|
|
);
|
|
|
|
assert.equal(
|
|
countMatches(overseasDelivery, /id=["']page-outbound-exception["']/g),
|
|
0,
|
|
'海外派送模块仍包含 page-outbound-exception',
|
|
);
|
|
assert.equal(
|
|
countMatches(customerService, /id=["']page-outbound-exception["']/g),
|
|
1,
|
|
'客户服务模块必须且只能包含一个 page-outbound-exception',
|
|
);
|
|
|
|
const exceptionPage = pageSource(customerService, 'outbound-exception');
|
|
assert.match(
|
|
exceptionPage,
|
|
/class=["']breadcrumb["'][^>]*>[\s\S]*?客户服务[\s\S]*?<strong>\s*异常订单\s*<\/strong>/,
|
|
'异常订单页面面包屑必须归属客户服务',
|
|
);
|
|
assert.match(
|
|
exceptionPage,
|
|
/onclick=["']switchPage\(\s*['"]outbound-dispatch['"]\s*,\s*this\s*\)["'][^>]*>\s*返回派送单\s*<\/button>/,
|
|
'异常订单页面必须保留原有返回派送单链接',
|
|
);
|
|
|
|
assert.match(
|
|
app,
|
|
/if\s*\(\s*page\s*===\s*['"]outbound-exception['"]\s*\)\s*renderDispatchExceptions\s*\(\s*\)\s*;/,
|
|
'app.js 必须继续通过 renderDispatchExceptions() 渲染 outbound-exception',
|
|
);
|
|
|
|
console.log('CUSTOMER_SERVICE_EXCEPTION_ORDERS_CHECK_PASS');
|