From cfd89ba570fa3bbf7cc537e3574c292a894e866f Mon Sep 17 00:00:00 2001 From: Suzumiya Date: Fri, 11 Sep 2026 20:23:10 +0800 Subject: [PATCH] =?UTF-8?q?=E2=91=A2=20=E9=A9=B1=E9=80=90=E7=94=A8?= =?UTF-8?q?=E4=BE=8B=E6=8A=97=E5=B9=B6=E5=8F=91=E8=B4=9F=E8=BD=BD=EF=BC=9A?= =?UTF-8?q?=E4=B8=80=E6=AC=A1=E7=81=8C=E6=BB=A1=E6=9B=BF=E4=BB=A3=2048=20?= =?UTF-8?q?=E8=BD=AE=E9=80=90=E5=BC=A0=E7=AD=89=E5=BE=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 现象:驱逐用例逐张 waitFor 48 张(3 个读取槽 + 48 轮 act/轮询)在同树多个写者并发跑测试时,会把用例 5s 超时耗光(Test timed out in 5000ms),红的是超时不是断言; - 改法:48 张一次性入队,只等"读取都已发出"(read 次数 ≥ 49),不再逐张断言 48 个卡的状态; - 原因说明:驱逐本来就会连锁(目标卡被驱逐 → 补扫描重读 → 再挤掉一张未被观察的填充卡),逐张断言会在链条行进中读到 undefined,红的是时序不是契约; - 核心断言一条不动:目标卡必须被重新请求(读次数 1 → 2)且最终回到 loaded;本用例超时放宽到 60s、内部 waitFor 20s; - 验证:改动前后各连跑 6 轮 + 4 路并发同时跑两个用例文件,全绿。 --- .../useProjectResourceCardPreviews.test.ts | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/apps/ai-game-creator-shell/tests/useProjectResourceCardPreviews.test.ts b/apps/ai-game-creator-shell/tests/useProjectResourceCardPreviews.test.ts index b94b4bf58..a8360a4a4 100644 --- a/apps/ai-game-creator-shell/tests/useProjectResourceCardPreviews.test.ts +++ b/apps/ai-game-creator-shell/tests/useProjectResourceCardPreviews.test.ts @@ -1920,7 +1920,7 @@ describe('冷启动首屏的放行范围与放行顺序', () => { } // 首屏要保证有图可读:可见的 12 张一张都不能少。 expect(readPathsSet.size).toBe(resources.length - offscreen.length); - }); + }, 30000); it('releases intersecting cards in two bands: viewport first, margin second', async () => { // B:一次 observer 回调可能同时报来 ~21 张相交卡,物理读取只有 3 个槽。 @@ -2037,16 +2037,31 @@ describe('预览缓存驱逐后的可见性复核', () => { expect(targetReads()).toHaveLength(1); // 灌满缓存:第 49 张落地时把最早的、仍然可见的这张挤出去。 - for (const filler of fillers) { - const identity = result.current.identityByResourceId.get(filler.id)!; - act(() => result.current.requestPreview(filler, identity, 'visible')); - await waitFor(() => - expect(result.current.previews.get(identity)?.status).toBe('loaded'), - ); - } + // + // 一次性把 48 张都排进队列、只等"读取都发出去了",**不逐张断言 48 个卡的状态**: + // 驱逐本来就会往后连锁(目标卡被驱逐 → 补扫描重读 → 再挤掉一张别人), + // 逐张断言会在链条行进中读到 `undefined`,红的是时序不是契约。 + act(() => { + for (const filler of fillers) { + result.current.requestPreview( + filler, + result.current.identityByResourceId.get(filler.id)!, + 'visible', + ); + } + }); + await waitFor( + () => + expect(previewReadCalls(invoke).length).toBeGreaterThanOrEqual( + fillers.length + 1, + ), + { timeout: 20000 }, + ); // 驱逐后必须补一次可见性复核:仍可见的卡要重新入队并重新读到图。 - await waitFor(() => expect(targetReads()).toHaveLength(2)); + await waitFor(() => expect(targetReads()).toHaveLength(2), { + timeout: 20000, + }); expect(result.current.previews.get(targetIdentity)?.status).toBe('loaded'); - }); + }, 60000); });