From c65ef8b7f0948e93a1c0a2ac2ff1548c692f99f4 Mon Sep 17 00:00:00 2001 From: NekoPunch Date: Sat, 5 Sep 2026 22:55:09 -0700 Subject: [PATCH] test(storybook): wait for plus-menu popups to settle jest-dom's toBeVisible reads the Astryx layer's computed opacity, which stays 0 until the first frame ticks its backwards-filled entry animation. On a loaded CI runner that frame lands after the assertion and a popup that never closed reads as hidden. Retry the visibility reads the way the slash-menu story already does, and let the refresh harness settle on an explicit release instead of a 150ms timer that a slow runner outlives before the click. Generated-by: Claude Code --- apps/desktop/stories/app-shell.stories.tsx | 15 ++++++++++----- .../stories/composer-slash-menu.stories.tsx | 7 ++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/desktop/stories/app-shell.stories.tsx b/apps/desktop/stories/app-shell.stories.tsx index 660cbe41a3..1db945f840 100644 --- a/apps/desktop/stories/app-shell.stories.tsx +++ b/apps/desktop/stories/app-shell.stories.tsx @@ -1492,6 +1492,9 @@ export const PlanAndSwarmModeOn: Story = { ), }; +/** Settles the Skill refresh the Plan toggle below started. */ +let releaseSkillRefresh: (() => void) | undefined; + function PlusMenuRefreshHarness() { const [planModeActive, setPlanModeActive] = useState(false); const [skillsLoading, setSkillsLoading] = useState(false); @@ -1506,7 +1509,7 @@ function PlusMenuRefreshHarness() { onPlanModeChange(active) { setPlanModeActive(active); setSkillsLoading(true); - window.setTimeout(() => setSkillsLoading(false), 150); + releaseSkillRefresh = () => setSkillsLoading(false); }, }} /> @@ -1535,7 +1538,7 @@ export const PlusMenuDuringSkillRefresh: Story = { expect(Math.abs(menu.getBoundingClientRect().height - height)).toBeLessThanOrEqual(0.5); await userEvent.click(skillsRow); - await expect(menu).toBeVisible(); + await waitFor(() => expect(menu).toBeVisible(), { timeout: 5_000 }); const editor = canvasElement.querySelector( '.maka-composer-editor [contenteditable="true"]', ); @@ -1543,6 +1546,7 @@ export const PlusMenuDuringSkillRefresh: Story = { await expect(editor).toHaveTextContent(''); await expect(page.queryByRole('listbox', { name: /技能/ })).not.toBeInTheDocument(); + releaseSkillRefresh?.(); await waitFor(() => { const settledRow = within( page.getByRole('menu', { name: '添加上下文' }), @@ -1553,9 +1557,10 @@ export const PlusMenuDuringSkillRefresh: Story = { page.getByRole('menu', { name: '添加上下文' }), ).getByRole('menuitem', { name: /选择技能/ }); await userEvent.click(settledRow); - await expect(await page.findByRole('listbox', { name: /技能/ }, { - timeout: 5_000, - })).toBeVisible(); + await waitFor( + () => expect(page.getByRole('listbox', { name: /技能/ })).toBeVisible(), + { timeout: 5_000 }, + ); }, }; diff --git a/apps/desktop/stories/composer-slash-menu.stories.tsx b/apps/desktop/stories/composer-slash-menu.stories.tsx index 07d6d1dd7d..9d8decba28 100644 --- a/apps/desktop/stories/composer-slash-menu.stories.tsx +++ b/apps/desktop/stories/composer-slash-menu.stories.tsx @@ -450,8 +450,9 @@ export const ContextSwitchStartsWithALoadingCatalog: Story = { page.getByRole('menu', { name: '添加上下文' }), ).getByRole('menuitem', { name: /选择技能/ }); await userEvent.click(settledRow); - await expect(await page.findByRole('listbox', { name: /技能/ }, { - timeout: 5_000, - })).toBeVisible(); + await waitFor( + () => expect(page.getByRole('listbox', { name: /技能/ })).toBeVisible(), + { timeout: 5_000 }, + ); }, };