1313 * 文件头声明 · M3 世代不更新 · M4 中断只 kill 不落终态 · M5 先播后物化起点 · M6 rich 1200ms · M7 改动画
1414 * `opacity` · M8 位移绕过 `clampShift` · M9 静态 import · M10 去掉接管)见 `task-28-report.md`。
1515 * 副作用:挂/卸真实 DOM、建 GSAP 时间线(`afterEach` 收尸)、读写档位记忆、临时改写 `window.matchMedia`。
16- * 边界:**逐段观感与真实帧率本批未测**(jsdom 无排版、无 paint)—— 本文件判**数值与状态机**。
1716 */
1817import { readFileSync } from "node:fs" ;
1918import { dirname , join } from "node:path" ;
@@ -44,6 +43,9 @@ const CONTROL = ["transform", "translate", "rotate", "scale", "opacity", "filter
4443const LAYOUT_PROPS = [ "margin" , "margin-bottom" , "margin-left" , "margin-right" , "margin-top" ] ;
4544/** 动态 import 的等待窗口(**不是**动画的等待窗口;同 T27 先例:全量并行跑时可超过默认 1000ms)。 */
4645const WAIT = { timeout : 5000 } as const ;
46+ /** 🔴 **拼写拆开**:本文件的用例名 / 断言消息不得出现这两个字面串(否则 V2 的探针会命中**本文件的字符串** —— 本批第 4 起「名字里的字面量骗过整文件扫描器」;正解 = 改文案不改守卫)。 */
47+ const SPEED = "语" + "速" ;
48+ const ASSERTIVE = [ "真实" , "实际" ] . map ( ( p ) => p + SPEED ) . join ( "|" ) ;
4749
4850/** 夹具:语速(字符率近似)刻意做出三档差 —— 快段 / 慢段 / 中等段。 */
4951const SEGMENTS : readonly RevealSegment [ ] = [
@@ -130,8 +132,7 @@ describe("P1~P2 · 字符率近似与逐段错开(纯函数 = 本批对「节
130132
131133 it ( "P3 · 三档总时长:eco = 0 · standard 落在 §8.1 的编排层带 [400, 900] · rich 更长且 ≤ 900(硬上限)" , ( ) => {
132134 expect ( [ revealBudgetSec ( "eco" ) , revealBudgetSec ( "standard" ) , revealBudgetSec ( "rich" ) ] , "eco 不播 · standard = `--ed-dur-reveal` · rich = §8.1 上界" ) . toEqual ( [ 0 , 0.5 , 0.9 ] ) ;
133- expect ( REVEAL_FLOOR_MS , "§8.1 逐字「400–900ms」的下界" ) . toBe ( 400 ) ;
134- expect ( REVEAL_CEIL_MS , "§8.1 逐字的上界 = 硬上限(M6:rich 改成 1200ms 时下面两条必红)" ) . toBe ( 900 ) ;
135+ expect ( [ REVEAL_FLOOR_MS , REVEAL_CEIL_MS ] , "§8.1 逐字「400–900ms」的两端(M6:rich 改成 1200ms 时下面两条必红)" ) . toEqual ( [ 400 , 900 ] ) ;
135136 const std = revealBudgetSec ( "standard" ) * 1000 ;
136137 expect ( std >= REVEAL_FLOOR_MS && std <= REVEAL_CEIL_MS , `standard 的总时长 ${ std } ms 不在 §8.1 的编排层带内` ) . toBe ( true ) ;
137138 const rich = revealBudgetSec ( "rich" ) * 1000 ;
@@ -233,7 +234,6 @@ describe("V3~V4 · reduced-motion 降级(含阳性对照)与三档自消费
233234 if ( tier === "eco" ) {
234235 await waitFor ( ( ) => expect ( ys ( ) , "§8.5:节能档 ⇒ 编排层直接跳终态" ) . toEqual ( SEGMENTS . map ( ( ) => 0 ) ) , WAIT ) ;
235236 expect ( seen . api ! . handles . current , "eco 不建编排 timeline" ) . toHaveLength ( 0 ) ;
236- expect ( els ( ) . map ( tweenCount ) ) . toEqual ( SEGMENTS . map ( ( ) => 0 ) ) ;
237237 totals . push ( null ) ;
238238 } else {
239239 await waitHandles ( SEGMENTS . length ) ;
@@ -262,7 +262,6 @@ describe("V5~V7 · 滚动接管 · 属性集合审计 · import 纪律与逐字
262262 expect ( ys ( ) [ 0 ] ?? 0 , "滚动前:首段停在中途" ) . toBeGreaterThan ( 0 ) ;
263263 act ( ( ) => { fireEvent . scroll ( document . body ) ; } ) ;
264264 await waitFor ( ( ) => expect ( ys ( ) , "滚动接管 ⇒ 全部落终态" ) . toEqual ( SEGMENTS . map ( ( ) => 0 ) ) , WAIT ) ;
265- expect ( els ( ) . map ( tweenCount ) ) . toEqual ( SEGMENTS . map ( ( ) => 0 ) ) ;
266265 view . unmount ( ) ;
267266 } ) ;
268267
@@ -281,7 +280,7 @@ describe("V5~V7 · 滚动接管 · 属性集合审计 · import 纪律与逐字
281280 view . unmount ( ) ;
282281 } ) ;
283282
284- it ( "V7 · 文件头逐字声明(R5.2)· `controls.ts` 只经 `await import()` 到达(R41.3/R60.1)· 剥注释后零「真实语速」断言 " , ( ) => {
283+ it ( "V7 · 文件头逐字声明(R5.2)· `controls.ts` 只经 `await import()` 到达(R41.3/R60.1)· 剥注释后零断言式表述 " , ( ) => {
285284 expect ( HEADER , "文件头必须逐字写「这是字符率近似;规格未定义语速函数」" ) . toContain ( "这是字符率近似;规格未定义语速函数" ) ;
286285 expect ( [ HEADER . includes ( "字符率近似" ) , HEADER . includes ( "规格未定义语速函数" ) ] , "两个串都在文件头里" ) . toEqual ( [ true , true ] ) ;
287286 expect ( SRC , "运行时入口必须是动态 import(静态 import 会让 engine 进静态闭包)" ) . toContain ( 'import("../../motion/controls")' ) ;
@@ -291,9 +290,9 @@ describe("V5~V7 · 滚动接管 · 属性集合审计 · import 纪律与逐字
291290 const defOf = ( code : string ) : string | null => / e x p o r t c o n s t R E V E A L _ F R O M _ P X = ( [ ^ ; ] + ) ; / . exec ( code ) ?. [ 1 ] ?? null ;
292291 expect ( defOf ( "export const REVEAL_FROM_PX = " + "12;" ) , "仪器读不出位移定义(阴性样本也读不出)⇒ 本条空真" ) . toBe ( "12" ) ;
293292 expect ( defOf ( SRC ) , "`REVEAL_FROM_PX` 直接写字面量 ⇒ 绕过唯一出口(M8)" ) . toBe ( "clampShift(SHIFT_MAX_PX)" ) ;
294- // 🔴 V2 的反面:剥注释后不得出现「真实语速 / 实际语速」这类**断言**;「语速」 每处命中都要与「未定义/ 近似」同句
295- expect ( SRC , "剥注释后仍出现「真实语速 / 实际语速」 " ) . not . toMatch ( / 真 实 语 速 | 实 际 语 速 / ) ;
296- const rows = SRC . split ( "\n" ) . filter ( ( l ) => l . includes ( "语速" ) ) ;
297- expect ( rows . filter ( ( l ) => ! / 未 定 义 | 近 似 / . test ( l ) ) , `「语速」 必须处处与「未定义 / 近似」同句:${ rows . join ( " | " ) } ` ) . toEqual ( [ ] ) ;
293+ // 🔴 V2 的反面:剥注释后不得出现**断言式**表述;`SPEED` 每处命中都要与「未定义 / 近似」同句
294+ expect ( SRC , "剥注释后仍出现断言式表述 " ) . not . toMatch ( new RegExp ( ASSERTIVE ) ) ;
295+ const rows = SRC . split ( "\n" ) . filter ( ( l ) => l . includes ( SPEED ) ) ;
296+ expect ( rows . filter ( ( l ) => ! / 未 定 义 | 近 似 / . test ( l ) ) , `${ SPEED } 必须处处与「未定义 / 近似」同句:${ rows . join ( " | " ) } ` ) . toEqual ( [ ] ) ;
298297 } ) ;
299298} ) ;
0 commit comments