文件
Henglianshutong/tests/verify_commission_level_spec.js

125 行
5.6 KiB
JavaScript

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

const fs = require('fs');
const path = require('path');
const vm = require('vm');
let passed = 0;
let failed = 0;
function assert(condition, testName, detail = '') {
if (condition) {
console.log(` [PASS] ${testName}`);
passed++;
} else {
console.error(` [FAIL] ${testName} - ${detail}`);
failed++;
}
}
console.log("========================================================");
console.log(" 身份等级 (shopro/commission/level) 页面与权限 TDD 测试");
console.log("========================================================\n");
// 1. 验证 Level.php 控制器存在与安全性
const levelPhpPath = path.resolve(__dirname, '../application/admin/controller/shopro/commission/Level.php');
assert(fs.existsSync(levelPhpPath), 'Level.php 控制器文件存在');
const levelPhpContent = fs.readFileSync(levelPhpPath, 'utf-8');
// 1.1 验证无临时 $noNeedLogin 遗留(后台安全保障)
assert(!levelPhpContent.includes('protected $noNeedLogin'), '无临时 $noNeedLogin 遗留(必须验证登录态)');
// 1.2 验证 $noNeedRight 包含 index 和 select(允许登录管理员正常进入列表)
const hasNoNeedRightIndex = /protected\s+\$noNeedRight\s*=\s*\[.*'index'.*\];/s.test(levelPhpContent);
const hasNoNeedRightSelect = /protected\s+\$noNeedRight\s*=\s*\[.*'select'.*\];/s.test(levelPhpContent);
assert(hasNoNeedRightIndex && hasNoNeedRightSelect, '$noNeedRight 必须包含 index 和 select', '缺少 index 或 select');
// 1.3 验证移除所有临时调试探针代码
assert(!levelPhpContent.includes('test_admin'), '已彻底清除 test_admin 模拟登录调试代码');
assert(!levelPhpContent.includes('read_err_log'), '已彻底清除 read_err_log 日志探测代码');
assert(!levelPhpContent.includes('INIT_ERROR'), '已彻底清除临时 INIT_ERROR 诊断代码');
assert(!levelPhpContent.includes('INDEX_ERROR'), '已彻底清除临时 INDEX_ERROR 诊断代码');
// 1.4 验证核心方法完整性
const requiredMethods = ['_initialize', 'index', 'add', 'edit', 'detail', 'delete', 'select'];
requiredMethods.forEach(method => {
assert(levelPhpContent.includes(`public function ${method}`), `包含动作方法: ${method}`);
});
// 2. 验证前端 JS (level.js) 语法与逻辑完整性
const levelJsPath = path.resolve(__dirname, '../public/assets/js/backend/shopro/commission/level.js');
assert(fs.existsSync(levelJsPath), 'level.js 前端脚本存在');
const levelJsContent = fs.readFileSync(levelJsPath, 'utf-8');
let jsSyntaxOk = false;
let jsSyntaxError = '';
try {
new vm.Script(levelJsContent, { filename: 'level.js' });
jsSyntaxOk = true;
} catch (e) {
jsSyntaxError = e.message;
}
assert(jsSyntaxOk, 'level.js 语法无 SyntaxError', jsSyntaxError);
// 2.1 模拟执行并检查 Controller 结构
const dummyDefine = function (deps, factory) {
const $ = () => ({});
const Backend = { api: {} };
const Table = {};
const Form = {};
return factory($, undefined, Backend, Table, Form);
};
let moduleLoaded = false;
let controllerObj = null;
try {
const sandbox = {
define: dummyDefine,
console: console,
location: { search: '?ref=addtabs' },
window: {},
Fast: { api: { ajax: () => {}, open: () => {}, fixurl: (u) => u } },
Vue: {
ref: (v) => ({ value: v }),
reactive: (o) => o,
onMounted: (cb) => cb(),
},
};
vm.createContext(sandbox);
controllerObj = vm.runInContext(levelJsContent, sandbox);
moduleLoaded = !!(controllerObj && controllerObj.index);
} catch (e) {
console.error("level.js 模拟加载异常:", e.message);
}
assert(moduleLoaded, 'level.js 包含 Controller.index 动作');
// 3. 验证视图模板存在且无语法残缺
const levelHtmlPath = path.resolve(__dirname, '../application/admin/view/shopro/commission/level/index.html');
assert(fs.existsSync(levelHtmlPath), 'index.html 视图模板文件存在');
const levelHtmlContent = fs.readFileSync(levelHtmlPath, 'utf-8');
assert(levelHtmlContent.includes('身份等级'), '模板包含身份等级标题');
assert(levelHtmlContent.includes('commission_rules?.commission_1'), '模板具备佣金比例安全可选链展示');
assert(levelHtmlContent.includes('state.makerBonus'), '模板具备创客进阶基数展示');
// 4. 验证 deploy.sh 对 runtime 目录的权限保障
const deployShPath = path.resolve(__dirname, '../scripts/deploy.sh');
assert(fs.existsSync(deployShPath), 'deploy.sh 部署脚本存在');
const deployShContent = fs.readFileSync(deployShPath, 'utf-8');
assert(deployShContent.includes('chown -R ${WEB_USER}:${WEB_USER} "${PROJECT_DIR}/runtime"'), '部署脚本包含 runtime 目录所有权赋予 www 用户');
assert(deployShContent.includes('chmod -R 777 "${PROJECT_DIR}/runtime"') || deployShContent.includes('chmod -R 775 "${PROJECT_DIR}/runtime"'), '部署脚本包含 runtime 目录写权限');
// 5. 验证生产异常模板 think_exception.tpl 干净无调试代码泄露
const exceptionTplPath = path.resolve(__dirname, '../application/common/view/tpl/think_exception.tpl');
assert(fs.existsSync(exceptionTplPath), 'think_exception.tpl 存在');
const exceptionTplContent = fs.readFileSync(exceptionTplPath, 'utf-8');
assert(!exceptionTplContent.includes('$exception instanceof \\Throwable'), 'think_exception.tpl 已恢复干净,无临时注入调试代码');
console.log(`\n测试统计: 通过: ${passed}, 失败: ${failed}`);
if (failed > 0) {
console.error(" 自动化测试未全部通过,需要继续修复!");
process.exit(1);
} else {
console.log(" 全部自动化测试通过!");
process.exit(0);
}