This commit is contained in:
2026-09-12 13:59:12 +08:00
commit 941ce4baab
71 changed files with 13037 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
'use strict';
const assert = require('node:assert');
const fs = require('node:fs');
const path = require('node:path');
const rendererSrc = fs.readFileSync(
path.join(__dirname, '..', 'renderer', 'renderer.js'), 'utf8'
);
let passed = 0;
function check(name, fn) {
try { fn(); console.log(' ok -', name); passed++; }
catch (e) { console.error(' FAIL -', name, e.message); process.exitCode = 1; }
}
// ---------- buildCard 抽函数 ----------
check('renderer.js 定义了 buildCard 函数', () => {
assert.ok(
/function\s+buildCard\s*\(/.test(rendererSrc),
'找不到 buildCard(c, i) 定义'
);
});
check('render() 调用 buildCard 而不是手写卡片构建', () => {
const renderFn = rendererSrc.match(/function\s+render\s*\(\s*\)\s*\{[\s\S]*?\n\}/);
assert.ok(renderFn, '找不到 render()');
assert.ok(
/buildCard\s*\(/.test(renderFn[0]),
'render() 没调用 buildCard'
);
// 抽函数后render() 内不应该有 cloneNode(true) 这种属于 buildCard 的细节
assert.ok(
!/cloneNode\s*\(\s*true\s*\)/.test(renderFn[0]),
'render() 还在做 cloneNodebuildCard 抽得不够彻底'
);
});
// ---------- onAdded 增量插入路径 ----------
check('onAdded 在 history Tab + 无搜索时走 prepend 而非 reload', () => {
const onAdded = rendererSrc.match(/onAdded\s*\(\s*\(\s*\w+\s*\)\s*=>\s*\{[\s\S]*?\}\s*\)/);
assert.ok(onAdded, '找不到 onAdded 回调');
// 存在非 reload 的快路径增量插入。reload 只应出现在跳过分支(收藏 Tab/
// 搜索中)和 catch 兜底里 —— 最多 2 次。快路径由下一条断言insertBefore/
// unshift单独保证。原计划写死 <=1 与 spec 强制的 catch fallback 冲突,
// 这里修正为 <=2 以匹配 spec见 task-7 报告的 controller addendum
const reloadCount = (onAdded[0].match(/\breload\s*\(/g) || []).length;
assert.ok(reloadCount <= 2, `onAdded 内 reload 次数 ${reloadCount},应是跳过分支 + catch 兜底 ≤ 2 次`);
// 应该有 prepend 路径或 append 增量逻辑
assert.ok(
/insertBefore|prepend|unshift/.test(onAdded[0]),
'onAdded 没走增量插入路径(看不到 insertBefore / unshift'
);
});
check('onAdded 跳过条件:搜索框非空或非 history Tab', () => {
const onAdded = rendererSrc.match(/onAdded\s*\(\s*\(\s*\w+\s*\)\s*=>\s*\{[\s\S]*?\}\s*\)/);
assert.ok(onAdded, '找不到 onAdded 回调');
assert.ok(
/currentTab\s*!==\s*'history'/.test(onAdded[0]),
'onAdded 没判断非 history Tab 时跳过 prepend'
);
assert.ok(
/\$search\.value\.trim\s*\(\s*\)\s*!==\s*''/.test(onAdded[0]),
'onAdded 没判断搜索框非空时跳过 prepend'
);
});
// ---------- 增量插入的两个回归坑 ----------
check('prependClip 熄灭空状态(#empty', () => {
// 空列表时 render() 亮起 #empty第一条增量不走 render()
// 不主动隐藏就会出现"卡片 + 暂无内容"同屏。
const prepend = rendererSrc.match(/function\s+prependClip\s*\([\s\S]*?\n\}/);
assert.ok(prepend, '找不到 prependClip()');
assert.ok(
/\$empty\.classList\.add\(\s*'hidden'\s*\)/.test(prepend[0]),
'prependClip 没有隐藏 #empty —— 空列表收到第一条增量时空状态不熄灭'
);
});
check('buildCard 的点击选中按运行时下标,不捕获构建时 i', () => {
// prependClip 会把已有卡片整体后移,捕获构建时下标的闭包会选中错误的项。
assert.ok(
/node\.onclick\s*=\s*\(\)\s*=>\s*select\(\s*\$cards\.indexOf\(node\)\s*\)/.test(rendererSrc),
'node.onclick 应在点击时从 $cards 现取下标select($cards.indexOf(node))),而不是捕获构建时的 i'
);
});
console.log(`\n${passed} checks passed`);