Skip to content

Commit f7ac5d0

Browse files
committed
test(shell): 拆件后既有断言改指新家
1 parent fa45caf commit f7ac5d0

4 files changed

Lines changed: 31 additions & 11 deletions

File tree

‎app/src/components/toastMigration.test.tsx‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,12 @@ const selfDrawnHits = (s: string): string[] =>
5252

5353
/** 三个实现文件(页级/hook 式/全局)—— 第 ④ 套是消费者,另有判据 */
5454
const IMPL_FILES = ["App.tsx", "pages/SessionsPage.tsx", "hooks/useTransientToast.tsx"] as const;
55+
/** 批 7 T1:全局 AI toast 的**装配件**从 `App.tsx` 抽到 `shell/aiToast.tsx`(纯搬迁,签名与三个字面量
56+
* 逐字不变)⇒ 断言「该链路的实现体在哪」的两条随之换新家;`App.tsx` 仍是**调用点**(§① 第 3 条守它,
57+
* §① 的域仍是「三套实现」(页级 / hook 式 / 全局),故本文件只增读一个新家、不改域)。 */
58+
const MOVED_IMPL = "shell/aiToast.tsx";
5559
const CODE: Readonly<Record<string, string>> = Object.fromEntries(
56-
IMPL_FILES.map((f) => [f, stripComments(read(f))]),
60+
[...IMPL_FILES, MOVED_IMPL].map((f) => [f, stripComments(read(f))]),
5761
);
5862

5963
/** barrel 名字表 / 深导入(`./ui/primitives` 与 `../ui/primitives` 都算 barrel) */
@@ -121,8 +125,10 @@ describe("① 三个实现文件剥注释后 0 处自绘浮动 toast 特征", ()
121125
});
122126

123127
describe("② 三条链路都经 barrel 到达 `Toast`(ADR-033 §1;深导入禁止)", () => {
124-
it("App.tsx / useTransientToast.tsx 的 barrel 名字表含 Toast,且无深导入", () => {
125-
for (const f of ["App.tsx", "hooks/useTransientToast.tsx"]) {
128+
it("shell/aiToast.tsx / useTransientToast.tsx 的 barrel 名字表含 Toast,且无深导入", () => {
129+
// 批 7 T1:AI toast 的 barrel 接缝随装配件搬到 `shell/aiToast.tsx`(`App.tsx` 已不再 import 原语)
130+
// —— 判据强度不降:同一条 `RE_BARREL` + `RE_DEEP`,只是文件键换成实现体所在的新家。
131+
for (const f of [MOVED_IMPL, "hooks/useTransientToast.tsx"]) {
126132
expect(barrelNames(CODE[f]), `${f} 未走 barrel`).toContain("Toast");
127133
expect(RE_DEEP.test(CODE[f]), `${f} 深导入了原语(会漏掉 motion.css 的 reduced-motion 块)`).toBe(false);
128134
}
@@ -142,9 +148,11 @@ describe("② 三条链路都经 barrel 到达 `Toast`(ADR-033 §1;深导入
142148
});
143149

144150
describe("③ durationMs 逐处显式(防「统一成默认 3000」)", () => {
145-
it("App.tsx 显式 3500(原值逐字保留)· SessionsPage 显式 3000 · hook 的原语时长为 0", () => {
146-
expect(CODE["App.tsx"]).toContain("durationMs={3500}");
147-
expect(CODE["App.tsx"]).not.toContain("durationMs={3000}");
151+
it("shell/aiToast.tsx 显式 3500(原值逐字保留)· SessionsPage 显式 3000 · hook 的原语时长为 0", () => {
152+
// 批 7 T1:`durationMs={3500}` 与 `AiToast` 的定义体一起搬到 `shell/aiToast.tsx`(字面量逐字不变)
153+
// —— 判据强度不降:仍是「实现体里显式 3500 且没有 3000」,只是文件键换新家。
154+
expect(CODE[MOVED_IMPL]).toContain("durationMs={3500}");
155+
expect(CODE[MOVED_IMPL]).not.toContain("durationMs={3000}");
148156
expect(CODE["pages/SessionsPage.tsx"]).toContain("useTransientToast(3000)");
149157
// hook 保留自己的状态机(计时权在 hook,单计时器)⇒ 原语侧显式 0(边界④「不自动消失」)
150158
expect(CODE["hooks/useTransientToast.tsx"]).toContain("durationMs={0}");

‎app/src/shell/ShellFallback.test.tsx‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ describe("叶级错误边界 SlotErrorBoundary", () => {
157157
});
158158
});
159159

160+
/** 批 7 T1:`PageSlot` 的**定义体**搬到 `shell/PageSlot.tsx`(纯搬迁,逐字不变)⇒ 「定义包住 children」
161+
* 这条改读新家;`App.tsx` 侧的**调用点形状**判据(§① 的 9 槽位、② 的三个窗口变体段)一个不动。 */
162+
const PAGE_SLOT = readFileSync(join(dirname(fileURLToPath(import.meta.url)), "PageSlot.tsx"), "utf8")
163+
.replace(/\r\n/g, "\n").replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
164+
160165
describe("结构尺:App.tsx 的边界**按槽位逐个判**(不用全文计数)", () => {
161166
const slots = [...APP.matchAll(/<PageSlot\b[^>]*>/g)].map((m) => m[0]);
162167

@@ -171,8 +176,9 @@ describe("结构尺:App.tsx 的边界**按槽位逐个判**(不用全文计
171176

172177
it("② 页级定义包住 children;overlay / float / dock 三处各有一个**包住面板**的边界", () => {
173178
const at = (s: string) => APP.indexOf(s);
174-
const ps = at("function PageSlot(");
175-
const def = APP.slice(ps, APP.indexOf("\n}\n", ps));
179+
const ps = PAGE_SLOT.indexOf("function PageSlot(");
180+
expect(ps, "PageSlot 定义体不在 shell/PageSlot.tsx(搬迁后误删 / 改成了别的形态)").toBeGreaterThan(-1);
181+
const def = PAGE_SLOT.slice(ps, PAGE_SLOT.indexOf("\n}\n", ps));
176182
const overlay = APP.slice(at('query.get("overlay") === "1"'), at('query.get("float") === "1"'));
177183
const float = APP.slice(at('query.get("float") === "1"'), at("<AppErrorBoundary>"));
178184
const dock = APP.slice(at("{dockMounted && ("), at("export default"));

‎app/src/shell/TopBar.test.tsx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ const CSS = readFileSync(join(HERE, "TopBar.css"), "utf8").replace(/\/\*[\s\S]*?
4545
const MOTION_CSS = readFileSync(join(HERE, "..", "ui", "primitives", "motion.css"), "utf8").replace(/\/\*[\s\S]*?\*\//g, "");
4646
const TOPBAR_TSX = readFileSync(join(HERE, "TopBar.tsx"), "utf8");
4747
const APP_TSX = readFileSync(join(HERE, "..", "App.tsx"), "utf8");
48+
const AI_TOAST_TSX = readFileSync(join(HERE, "aiToast.tsx"), "utf8"); // 批 7 T1:AI toast 装配件的新家(纯搬迁)——「交给 belowNav 档」改读它;「导航行里不再有它」两条仍读 App.tsx
4849
/**
4950
* App.tsx 的**只留代码**版本:剥块注释与整行 `//` 注释。
5051
* Why 必须剥:App.tsx 的注释里逐字出现了 `<nav>`、`zIndex("toast")` 这些判据串 —— 不剥的话
@@ -273,7 +274,7 @@ describe("裁决 A3:AI toast 不在导航行里", () => {
273274
// (B13 逐字要求);`ai-toast` 的 testid 语义改由**渲染级**断言保住(B15 ②),见
274275
// `components/toastMigration.test.tsx` §⑤(断言的是渲染出的元素,不是源码里出现过该字符串)。
275276
expect(TOAST_BASE_BODY, "原语基类不是 fixed 定位 ⇒ toast 仍会参与布局流向").toMatch(/position:\s*fixed/);
276-
expect(APP_CODE, "App.tsx 没有把 AI toast 交给 belowNav 档").toContain('placement="belowNav"');
277+
expect(AI_TOAST_TSX, "AI toast 没有交给 belowNav 档(批 7 T1:装配件已搬至 shell/aiToast.tsx)").toContain('placement="belowNav"');
277278
expect(TOAST_BELOW_NAV_BODY, "位置档的 top 没有消费壳层 token --ed-nav-h").toMatch(
278279
/top:\s*calc\(\s*var\(--ed-nav-h/,
279280
);

‎app/src/shell/navRegistry.test.ts‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ const APP_TSX = join(SRC, "App.tsx");
2929
const REGISTRY_TS = join(SRC, "shell", "navRegistry.ts");
3030
const PAGES = join(SRC, "pages");
3131
const appSource = () => readFileSync(APP_TSX, "utf8");
32+
/** 批 7 T1:`PageSlot` 的**定义体**从 `App.tsx` 抽到 `shell/PageSlot.tsx`(纯搬迁,逐字不变)
33+
* ⇒ 「display 门控而非卸载」那两条字面量判据改读新家;`mountedPages` 只增不变量仍读 `App.tsx`。 */
34+
const PAGE_SLOT_TSX = join(SRC, "shell", "PageSlot.tsx");
35+
const pageSlotSource = () => readFileSync(PAGE_SLOT_TSX, "utf8");
3236

3337
/** 页面文件(不含测试)—— 从目录枚举,不手写清单 */
3438
function pageFiles(): string[] {
@@ -142,8 +146,9 @@ describe("导航注册表(规格 §10 批 3「9 页全走注册表」)", ()
142146
const app = appSource();
143147
// 只增的更新式(逐字)—— 换成「按当前页重建集合」即「切走即卸载」,是本仓禁止形态
144148
expect(app).toContain("prev.has(page) ? prev : new Set(prev).add(page)");
145-
expect(app).toContain("if (!mounted) return null;");
146-
expect(app).toContain('display: show ? "block" : "none"');
149+
const slot = pageSlotSource();
150+
expect(slot, "PageSlot 定义体不在家(搬迁后误删,或门控被改成卸载)").toContain("if (!mounted) return null;");
151+
expect(slot, "PageSlot 不再用 display 门控(切页变成卸载 ⇒ 保活失效)").toContain('display: show ? "block" : "none"');
147152
expect(app).not.toMatch(/mountedPages\.delete\(/);
148153
expect(app).not.toMatch(/setMountedPages\(new Set\(\[page\]\)\)/);
149154
expect(app).not.toMatch(/setMountedPages\(\(\) =>/);

0 commit comments

Comments
 (0)