P1-6 useStyleLearn/useKimiOauth 修 stale-closure 依赖。 P1-7 CommandPalette/Drawer 加 focus trap(新 lib/a11y/focusTrap)。 P1-8 SSE 解析与 server.ts 去 as 强转改类型守卫/运行时校验。 P2 删冗余强转、开 noUncheckedIndexedAccess、Toast 清理+稳定 key、列表 key 稳定化、 rel=noopener、useMemo 大文本、ConflictCard role=group、useInjection 加锁、 client.test 真断言。 codegen 重生成 schema.d.ts + 消费 DimensionEntry/ReviewConflictView 强类型。
42 lines
1.6 KiB
TypeScript
42 lines
1.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
||
|
||
// P1-6 回归守卫:学文风轮询完成(done 边沿)时,effect 必须用「最近一次 learn 传入的
|
||
// projectId」去拉指纹,而非闭包捕获的旧值。useStyleLearn 用 ref 追踪 projectId 来保证这点。
|
||
//
|
||
// 该 hook 依赖浏览器/React 渲染,node 环境无法整体跑;这里以最小模型固化 ref 追踪契约:
|
||
// 切项目(连续两次 learn)后,done 时读到的应是后者,不会是首次的陈旧值。
|
||
describe("useStyleLearn projectId 追踪(P1-6 stale-closure 守卫)", () => {
|
||
// 复刻 hook 内部:learn 同步写 ref,done 时同步读 ref。
|
||
function makeTracker() {
|
||
const projectIdRef: { current: string | null } = { current: null };
|
||
return {
|
||
// learn(pid):受理时记录最近项目。
|
||
learn(pid: string): void {
|
||
projectIdRef.current = pid;
|
||
},
|
||
// onDone():轮询完成时取用于拉指纹的项目(应为最新)。
|
||
onDone(): string | null {
|
||
return projectIdRef.current;
|
||
},
|
||
};
|
||
}
|
||
|
||
it("done 时用最近一次 learn 的 projectId(切项目后不复用旧值)", () => {
|
||
// Arrange
|
||
const t = makeTracker();
|
||
|
||
// Act:先 learn 项目 A,再切到项目 B(模拟用户换项目重学),此时 A 的轮询尚未完成。
|
||
t.learn("project-A");
|
||
t.learn("project-B");
|
||
const used = t.onDone();
|
||
|
||
// Assert:done 边沿读到的是 B,而非闭包里陈旧的 A。
|
||
expect(used).toBe("project-B");
|
||
});
|
||
|
||
it("未 learn 时为 null(不误拉指纹)", () => {
|
||
const t = makeTracker();
|
||
expect(t.onDone()).toBeNull();
|
||
});
|
||
});
|