From e211589532858dc8919ebd2fec845f296585b0e8 Mon Sep 17 00:00:00 2001 From: Thomas Kosiewski Date: Mon, 15 Jun 2026 15:59:14 +0000 Subject: [PATCH] fix: stabilize settings experiment stories --- .../Sections/ExperimentsSection.stories.tsx | 5 ++- .../Sections/settingsStoryUtils.test.tsx | 31 +++++++++++++++++++ .../Settings/Sections/settingsStoryUtils.tsx | 15 +++++++-- 3 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 src/browser/features/Settings/Sections/settingsStoryUtils.test.tsx diff --git a/src/browser/features/Settings/Sections/ExperimentsSection.stories.tsx b/src/browser/features/Settings/Sections/ExperimentsSection.stories.tsx index ecbb0fada0..bb4bee0459 100644 --- a/src/browser/features/Settings/Sections/ExperimentsSection.stories.tsx +++ b/src/browser/features/Settings/Sections/ExperimentsSection.stories.tsx @@ -20,9 +20,8 @@ export const Experiments: Story = { setupSettingsStory({ - // Explicit off-override: experiment localStorage keys leak between - // stories in the same browser session, so seed the parent off to keep - // the "sub-experiments hidden" assertion order-independent. + // Seed the parent off explicitly so the "sub-experiments hidden" + // assertion does not rely on the experiment's default value. experiments: { [EXPERIMENT_IDS.MEMORY]: false }, }) } diff --git a/src/browser/features/Settings/Sections/settingsStoryUtils.test.tsx b/src/browser/features/Settings/Sections/settingsStoryUtils.test.tsx new file mode 100644 index 0000000000..67ce252028 --- /dev/null +++ b/src/browser/features/Settings/Sections/settingsStoryUtils.test.tsx @@ -0,0 +1,31 @@ +import { afterEach, beforeEach, describe, expect, test } from "bun:test"; +import { installDom } from "../../../../../tests/ui/dom"; +import { EXPERIMENT_IDS, getExperimentKey } from "@/common/constants/experiments"; +import { resetStorybookPersistedStateForStory, setupSettingsStory } from "./settingsStoryUtils"; + +describe("SettingsSectionStory", () => { + let restoreDom: (() => void) | null = null; + + beforeEach(() => { + restoreDom = installDom(); + }); + + afterEach(() => { + restoreDom?.(); + restoreDom = null; + }); + + test("clears unseeded experiment overrides before story setup", () => { + const key = getExperimentKey(EXPERIMENT_IDS.PROGRAMMATIC_TOOL_CALLING); + window.localStorage.setItem(key, JSON.stringify(true)); + + resetStorybookPersistedStateForStory(); + + expect(window.localStorage.getItem(key)).toBeNull(); + + setupSettingsStory({ + experiments: { [EXPERIMENT_IDS.PROGRAMMATIC_TOOL_CALLING]: true }, + }); + expect(window.localStorage.getItem(key)).toBe(JSON.stringify(true)); + }); +}); diff --git a/src/browser/features/Settings/Sections/settingsStoryUtils.tsx b/src/browser/features/Settings/Sections/settingsStoryUtils.tsx index 91b9b34aa5..96fedbce8d 100644 --- a/src/browser/features/Settings/Sections/settingsStoryUtils.tsx +++ b/src/browser/features/Settings/Sections/settingsStoryUtils.tsx @@ -14,7 +14,11 @@ import { selectWorkspace } from "@/browser/stories/helpers/uiState"; import { createWorkspace, groupWorkspacesByProject } from "@/browser/stories/mocks/workspaces"; import { createMockORPCClient } from "@/browser/stories/mocks/orpc"; import { getProvidersConfigStore } from "@/browser/stores/ProvidersConfigStore"; -import { getExperimentKey, type ExperimentId } from "@/common/constants/experiments"; +import { + getExperimentKey, + getExperimentList, + type ExperimentId, +} from "@/common/constants/experiments"; import { SELECTED_WORKSPACE_KEY, UI_THEME_KEY } from "@/common/constants/storage"; import type { ServerAuthSession } from "@/common/orpc/types"; import type { AgentAiDefaults } from "@/common/types/agentAiDefaults"; @@ -29,10 +33,17 @@ interface SettingsSectionStoryProps { children: ReactNode; } -function resetStorybookPersistedStateForStory(): void { +export function resetStorybookPersistedStateForStory(): void { if (typeof localStorage !== "undefined") { localStorage.removeItem(SELECTED_WORKSPACE_KEY); localStorage.setItem(UI_THEME_KEY, JSON.stringify("dark")); + + // Chromatic reuses one browser origin across stories, so experiment + // localStorage overrides from one story must not decide another story's + // switch positions. Each story can opt back in through setupSettingsStory(). + for (const experiment of getExperimentList()) { + localStorage.removeItem(getExperimentKey(experiment.id)); + } } }