From 0382cf73948c3ae05d0321409e773214b8db88ac Mon Sep 17 00:00:00 2001 From: Linghong Date: Wed, 16 Sep 2026 12:53:24 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=89=8D=E7=AB=AF=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E5=81=B6=E5=8F=91=E8=B6=85=E6=97=B6=E4=B8=8E=E5=BC=82?= =?UTF-8?q?=E6=AD=A5=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Direct 活动回合读取失败后的重试定时器随组件卸载清理,避免测试环境销毁后访问 window。 后台素材查询大量缩略图测试合并可见性触发,并补充独立超时预算。 创作首页活动图与资源卡预览调度重载用例分别补充独立超时预算。 清单快照测试补齐 Direct 活动回合 IPC mock,避免未预期命令进入重试。 --- .../pages/AdminEditorAssetQueryPage.test.tsx | 28 ++++++++++++++++--- .../agent-runtime/directActiveTurns.ts | 17 +++++++---- .../appSurface/project-development.suite.ts | 2 +- .../workspaceLauncherManifestMerge.test.tsx | 2 ++ .../CreationLandingView.test.tsx | 2 +- 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/apps/admin-web/src/pages/AdminEditorAssetQueryPage.test.tsx b/apps/admin-web/src/pages/AdminEditorAssetQueryPage.test.tsx index f262b8254..0feeb767d 100644 --- a/apps/admin-web/src/pages/AdminEditorAssetQueryPage.test.tsx +++ b/apps/admin-web/src/pages/AdminEditorAssetQueryPage.test.tsx @@ -38,6 +38,7 @@ vi.mock('../api/adminApiClient', () => ({ interface MockIntersectionObserverController { enter: (target: Element) => void; + enterAll: (targets: Element[]) => void; isObserved: (target: Element) => boolean; } @@ -106,6 +107,25 @@ function installIntersectionObserverMock(): MockIntersectionObserverController { ); }); }, + enterAll(targets) { + act(() => { + for (const target of targets) { + const record = observed.get(target); + if (!record) { + throw new Error('目标缩略图尚未进入 IntersectionObserver'); + } + record.callback( + [ + { + isIntersecting: true, + target, + } as IntersectionObserverEntry, + ], + record.observer, + ); + } + }); + }, isObserved(target) { return observed.has(target); }, @@ -753,10 +773,10 @@ test('后台素材查询为大量同时可见的缩略图持续错峰换签', as const thumbnails = entries.map((entry) => thumbnailElementForLabel(entry.label), ); - thumbnails.forEach((thumbnail) => { + for (const thumbnail of thumbnails) { expect(observer.isObserved(thumbnail)).toBe(true); - observer.enter(thumbnail); - }); + } + observer.enterAll(thumbnails); await act(async () => { await Promise.resolve(); }); @@ -776,7 +796,7 @@ test('后台素材查询为大量同时可见的缩略图持续错峰换签', as await vi.advanceTimersByTimeAsync(200); }); expect(getAdminAssetReadUrl).toHaveBeenCalledTimes(105); -}); +}, 10_000); test('后台素材查询读取更多后为新进入可视区域的素材换签', async () => { const observer = installIntersectionObserverMock(); diff --git a/apps/ai-game-creator-shell/src/features/agent-runtime/directActiveTurns.ts b/apps/ai-game-creator-shell/src/features/agent-runtime/directActiveTurns.ts index 0eadbeacd..58401f52a 100644 --- a/apps/ai-game-creator-shell/src/features/agent-runtime/directActiveTurns.ts +++ b/apps/ai-game-creator-shell/src/features/agent-runtime/directActiveTurns.ts @@ -38,11 +38,16 @@ export function useDirectActiveTurns({ const [snapshotReadFailed, setSnapshotReadFailed] = useState(false); const mountedRef = useRef(true); const inFlightRef = useRef | null>(null); + const retryTimerRef = useRef(null); useEffect(() => { mountedRef.current = true; return () => { mountedRef.current = false; + if (retryTimerRef.current !== null) { + window.clearTimeout(retryTimerRef.current); + retryTimerRef.current = null; + } }; }, []); @@ -73,12 +78,12 @@ export function useDirectActiveTurns({ return; } catch { if (attempt < DIRECT_ACTIVE_TURNS_READ_ATTEMPTS) { - await new Promise((resolve) => - window.setTimeout( - resolve, - DIRECT_ACTIVE_TURNS_READ_RETRY_DELAY_MS * attempt, - ), - ); + await new Promise((resolve) => { + retryTimerRef.current = window.setTimeout(() => { + retryTimerRef.current = null; + resolve(); + }, DIRECT_ACTIVE_TURNS_READ_RETRY_DELAY_MS * attempt); + }); } } } diff --git a/apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts b/apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts index 8ca03bfe5..51e004f20 100644 --- a/apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts +++ b/apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts @@ -3350,7 +3350,7 @@ export function registerProjectWorkbenchFoundationTests() { expect(URL.createObjectURL).toHaveBeenCalledTimes( objectUrlCountBeforeLateResult, ); - }); + }, 20_000); it('renders immutable manifest versions, their parent graph, and bound asset highlights', async () => { const manifest = createGameCreationAppManifest( diff --git a/apps/ai-game-creator-shell/tests/workspaceLauncherManifestMerge.test.tsx b/apps/ai-game-creator-shell/tests/workspaceLauncherManifestMerge.test.tsx index 28dde6e59..5ea530842 100644 --- a/apps/ai-game-creator-shell/tests/workspaceLauncherManifestMerge.test.tsx +++ b/apps/ai-game-creator-shell/tests/workspaceLauncherManifestMerge.test.tsx @@ -106,6 +106,8 @@ function installInvokeMock() { return { revision: HELD_REVISION }; case 'get_design_agent_runtime_mode': return null; + case 'list_game_creator_direct_active_turns': + return []; case 'read_project_permission_policy': return { projectPath: PROJECT_PATH, diff --git a/src/components/creation-home/CreationLandingView.test.tsx b/src/components/creation-home/CreationLandingView.test.tsx index 1785dad1d..d1f0f2b4e 100644 --- a/src/components/creation-home/CreationLandingView.test.tsx +++ b/src/components/creation-home/CreationLandingView.test.tsx @@ -1351,7 +1351,7 @@ describe('CreationLandingView', () => { `/api/assets/read-url?objectKey=${encodeURIComponent(campaignObjectKey)}`, expect.objectContaining({ method: 'GET' }), ); - }); + }, 10_000); it('loads more featured resources when the list reaches the end', async () => { const observers = installIntersectionObserverMock();