Files
docs/悦/货代SAAS平台后台/tests/verify-dispatch-docs-courier-alert.cjs
T
2026-08-21 09:20:26 +08:00

122 lines
6.8 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 app = fs.readFileSync(path.join(root, 'prototype-src/app.js'), 'utf8');
const overlays = fs.readFileSync(path.join(root, 'prototype-src/overlays.html'), 'utf8');
const shell = fs.readFileSync(path.join(root, 'prototype-src/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} 函数未正确闭合`);
}
assert.match(app, /key:'loadingPhotos',label:'装车照片',accept:'\.jpg,\.jpeg,\.png,\.webp'/, '缺少装车照片资料类型');
assert.match(app, /key:'courierReceiptScreenshots',label:'快递签收截图',accept:'\.jpg,\.jpeg,\.png,\.webp'/, '缺少快递签收截图资料类型');
assert.match(overlays, /id="dispatch-docs-summary">0\/7 已上传<\/strong>/, '资料弹窗初始汇总未更新为 7 类');
assert.match(app, /dispatchDocTypes\.length/, '资料摘要未使用资料类型总数动态计算');
const alertStateSource = extractFunction(app, 'getCourierAlertState');
assert.match(alertStateSource, /48\s*\*\s*60\s*\*\s*60\s*\*\s*1000/, '异常阈值不是完整 48 小时');
const context = { Date, Number, String, Boolean, Array };
vm.createContext(context);
vm.runInContext(`${alertStateSource};this.getCourierAlertState=getCourierAlertState;`, context);
const now = new Date('2026-08-13T12:00:00+08:00');
const baseRecord = {
status: '派送中',
expressNo: 'UPS-ALERT-001',
outboundAt: '2026-08-11 12:00:00',
courierNodes: []
};
assert.equal(context.getCourierAlertState(baseRecord, now).anomalous, true, '满 48 小时无节点应判定异常');
assert.equal(context.getCourierAlertState({...baseRecord, outboundAt: '2026-08-11 12:00:01'}, now).anomalous, false, '不足 48 小时不应判定异常');
assert.equal(context.getCourierAlertState({...baseRecord, courierNodes: [{time: '2026-08-12 08:00'}]}, now).anomalous, false, '已有任意快递节点不应判定异常');
assert.equal(context.getCourierAlertState({...baseRecord, status: '已签收'}, now).anomalous, false, '已签收不应保持异常');
assert.equal(context.getCourierAlertState({...baseRecord, expressNo: ''}, now).anomalous, false, '无快递单号不参与异常判定');
assert.equal(context.getCourierAlertState({...baseRecord, outboundAt: ''}, now).anomalous, false, '无明确出库时间不参与异常判定');
const createMessageSource = extractFunction(app, 'createCourierAlertMessage');
const formatTimeSource = extractFunction(app, 'formatCourierAlertTime');
const syncSource = extractFunction(app, 'syncCourierAlert');
const waybillSource = extractFunction(app, 'renderDispatchWaybillCell');
assert.match(createMessageSource, /msgManageData\.unshift/, '首次异常未写入消息管理');
assert.match(createMessageSource, /msgMyData\.unshift/, '首次异常未写入我的消息');
assert.match(createMessageSource, /type:'异常告警'/, '消息管理类型不是异常告警');
assert.match(createMessageSource, /target:'操作员'/, '消息管理接收对象不是操作员');
assert.match(createMessageSource, /status:'未读'/, '我的消息未标记为未读');
assert.match(createMessageSource, /暂无快递节点/, '内部提醒未说明暂无快递节点');
assert.doesNotMatch(createMessageSource, /短信|SMS/i, '快递异常提醒不应发送短信');
assert.match(syncSource, /courierAlertedAt/, '缺少异常提醒时间去重字段');
assert.match(syncSource, /courierAlertStatus=['"]异常['"]/, '缺少异常状态写入');
assert.match(syncSource, /courierAlertStatus=['"]已恢复['"]/, '缺少已恢复状态写入');
assert.match(syncSource, /courierRecoveredAt/, '缺少异常恢复时间');
assert.match(waybillSource, /row\.cells\[4\]/, '异常未应用到现有运单号单元格');
assert.match(waybillSource, /出库已满48小时,暂未查询到快递节点/, '缺少确认的悬停提示');
assert.match(waybillSource, /dispatch-waybill-alert/, '缺少异常运单号样式类');
assert.match(app, /renderDispatchWaybillCell\(record,row\)/, '静态和动态派送行未统一调用异常渲染');
assert.match(app, /expressNo:order\.expressNo\|\|''/, '动态派送未仅复制明确快递单号');
assert.match(app, /outboundAt:order\.outboundAt\|\|''/, '动态派送未仅复制明确出库时间');
assert.match(app, /status:'派送中'[^\n]+outboundAt:'2026-08-12 08:00:00',courierNodes:\[\]/, '静态样例缺少未满 48 小时且无节点的派送单');
assert.match(shell, /\.dispatch-waybill-alert\{[^}]*color:#dc2626!important/, '缺少异常运单号红色样式');
const alertRuntime = {
Date,
Number,
String,
Boolean,
Array,
msgManageData: [],
msgMyData: [],
lmoNow: () => '2026-08-13 12:00'
};
vm.createContext(alertRuntime);
vm.runInContext(
`${alertStateSource};${createMessageSource};${formatTimeSource};${syncSource};` +
'this.syncCourierAlert=syncCourierAlert;',
alertRuntime
);
const runtimeRecord = {...baseRecord, dispatchNo: 'DSP-ALERT-001'};
alertRuntime.syncCourierAlert(runtimeRecord, now);
alertRuntime.syncCourierAlert(runtimeRecord, now);
assert.equal(alertRuntime.msgManageData.length, 1, '持续异常重复渲染不应重复写入消息管理');
assert.equal(alertRuntime.msgMyData.length, 1, '持续异常重复渲染不应重复写入我的消息');
assert.equal(runtimeRecord.courierAlertStatus, '异常', '首次异常未记录异常状态');
assert.equal(runtimeRecord.courierAlertedAt, '2026-08-13 12:00', '首次异常未记录提醒时间');
runtimeRecord.courierNodes.push({time: '2026-08-13 12:10', status: '已揽收'});
alertRuntime.syncCourierAlert(runtimeRecord, new Date('2026-08-13T12:15:00+08:00'));
assert.equal(runtimeRecord.courierAlertStatus, '已恢复', '出现快递节点后未记录已恢复');
assert.equal(runtimeRecord.courierRecoveredAt, '2026-08-13 12:15', '出现快递节点后未记录恢复时间');
assert.equal(alertRuntime.msgManageData.length, 1, '异常恢复不应重复写入消息管理');
assert.equal(alertRuntime.msgMyData.length, 1, '异常恢复不应重复写入我的消息');
console.log('DISPATCH_DOCS_COURIER_ALERT_CHECK_PASS');