test(webui): 「滑动硬截断」诊断脚本(自带浏览器,不依赖共享实例)
用户:「webui 大片界面存在滑动硬截断」。
## 现状:这一轮我**没能复现**
量法是"内容溢出但没有可滚动祖先"⇒ 候选 0 个;换成用户视角四问
(有没有可滚动容器 / 能不能滚到底 / 末尾有没有被切 / 页面自己溢不溢出)后:
390×700 通信 ✅ 日历 ✅ 联系人 ✅ 我的 ✅
1400×700 通信 ✅ 日历 ✅ 联系人 ✅ 我的 ✅
(造了 12 个会话、正文都很长;验完已归档)
即按这四种量法都测不到硬截断。**长正文详情页**那一块我的探针超时没跑完 ⇒
**未判定**,不能算"没问题"。
## 这次的交付物
`client/electron/test/manual/scroll-cut-verify.mjs`:把上面这套量法固化下来,
并且**自带浏览器**(不连共享 9222)—— 共享实例被历次被中断的运行留下僵尸上下文后,
`connectOverCDP` 会一直超时(我这个会话里已经遇到三次),诊断脚本必须在
"共享实例状态未知"时也能跑。
## 我需要的(否则只能继续猜)
请指一下**具体页面 + 具体手势/位置**:哪一屏、滚轮还是触摸拖动、硬截断出现在
列表末尾还是详情正文?也可以直接看截图。我上一轮"窄屏显示不全"也是同样情况 ——
我量不出来、但你说有,那多半是我量的维度不对。
This commit is contained in:
@ -10,6 +10,7 @@
|
||||
import { readFileSync, readdirSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join } from 'node:path';
|
||||
import postcss from 'postcss';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const read = p => readFileSync(join(here, p), 'utf8');
|
||||
@ -213,7 +214,8 @@ check('新组件未使用未映射色族', unmapped.length === 0, unmapped.join(
|
||||
};
|
||||
walk(join(here, '../src'));
|
||||
const PAGE_BASE = new Set(['bg-gray-50', 'bg-slate-100']); // 页面底必须保持全透明
|
||||
const missing = [...used].filter(c => !PAGE_BASE.has(c) && !gen.includes(`.${c} {`));
|
||||
const manifest = [...used].filter(c => !PAGE_BASE.has(c));
|
||||
const missing = manifest.filter(c => !gen.includes(`.${c} {`));
|
||||
check('源码里用到的浅色表面类全被接管', missing.length === 0, `漏了:${missing.join(', ')}`);
|
||||
/*
|
||||
* ★ 生成文件的**头注释不能提前闭合**(2026-09-14 修,与上面那条同一根因的两个后果)。
|
||||
@ -242,6 +244,57 @@ check('新组件未使用未映射色族', unmapped.length === 0, unmapped.join(
|
||||
check('页面底没有被写进半透明清单', [...PAGE_BASE].every(b => !gen.includes(`.${b} {`)));
|
||||
check('清单不是空跑(至少扫到 10 个类)', used.size >= 10, `实际 ${used.size}`);
|
||||
|
||||
/*
|
||||
* ★ 生成产物"能被 CSS 解析器吃下"还是"只有浏览器能发现"(2026-09-14,pi 提议)。
|
||||
*
|
||||
* 上面那条查的是**文本**:剥掉注释后以第一条选择器起头。而"注释提前闭合"这个 bug
|
||||
* 更狠的形态是:那条规则在文本里**还在**,甚至在 postcss 里**也还是一条规则**
|
||||
* —— 但它的选择器前面粘上了注释的尾巴(当年构建只给一句
|
||||
* `[WARNING] Unexpected "14"`),于是浏览器按"选择器不匹配任何元素"整条丢掉。
|
||||
*
|
||||
* 所以光"能解析"不够(实测:postcss 对坏产物照样解析出 1 条规则,只是选择器变了),
|
||||
* 判据要卡的是**选择器的形状** + **规则条数**:
|
||||
* - 每条规则的选择器必须**恰好**是 `html[data-bg='on'] .bg-xxx`(多一个字符都不行);
|
||||
* - 规则条数必须等于源码里扫到的接管清单条数(多一条少一条都要红)。
|
||||
* 收获:把"生成器写坏产物"从"只有浏览器能发现"变成"跑判据就红"。
|
||||
*/
|
||||
const RULE_SHAPE = /^html\[data-bg='on'\] \.bg-[a-z]+-\d{2,3}$/;
|
||||
let parsedSelectors = null;
|
||||
let parseErr = '';
|
||||
try {
|
||||
parsedSelectors = postcss
|
||||
.parse(gen)
|
||||
.nodes.filter(n => n.type === 'rule')
|
||||
.map(n => n.selector);
|
||||
} catch (e) {
|
||||
parseErr = String(e && e.message ? e.message : e);
|
||||
}
|
||||
check('生成的接管 CSS 能被 CSS 解析器读下来', parseErr === '', parseErr);
|
||||
if (parsedSelectors !== null) {
|
||||
const malformed = parsedSelectors.filter(s => !RULE_SHAPE.test(s));
|
||||
check(
|
||||
'每条接管规则的选择器形状都与生成器一致(防注释尾巴粘进选择器)',
|
||||
malformed.length === 0,
|
||||
`异常选择器:${malformed.slice(0, 3).join(' | ')}`
|
||||
);
|
||||
check(
|
||||
'接管规则条数与源码扫到的清单条数一致',
|
||||
parsedSelectors.length === manifest.length,
|
||||
`规则 ${parsedSelectors.length} 条 / 清单 ${manifest.length} 个`
|
||||
);
|
||||
// 反向对照:用生成器**当年**的坏写法(注释里带"星号紧接斜杠")验证判据真的会红
|
||||
const broken = "/* 来自 src/**/*.tsx 的用法 */\nhtml[data-bg='on'] .bg-amber-100 { background: red }";
|
||||
const brokenSels = postcss
|
||||
.parse(broken)
|
||||
.nodes.filter(n => n.type === 'rule')
|
||||
.map(n => n.selector);
|
||||
check(
|
||||
'判据自检:注释提前闭合后,第一条规则的选择器必须被判为异常形状',
|
||||
brokenSels.length === 0 || brokenSels.some(s => !RULE_SHAPE.test(s)),
|
||||
`解析出:${brokenSels.join(' | ')}`
|
||||
);
|
||||
}
|
||||
|
||||
// 18) ★ 导航栏必须**完全不透明**、内容面板必须更通透、整体圆角玻璃化。
|
||||
//
|
||||
// 用户 2026-09-14 原话:「导航栏应当完全不透明……没有正文的位置过于不通透,
|
||||
|
||||
Reference in New Issue
Block a user