Skip to content

Addon-vitest: Add an initialGlobals option to pin a project's globals - #35226

Merged
Sidnioulz merged 1 commit into
storybookjs:nextfrom
lifeiscontent:lifeiscontent/addon-vitest-initial-globals
Jul 2, 2026
Merged

Sidnioulz merged 1 commit into
storybookjs:nextfrom
lifeiscontent:lifeiscontent/addon-vitest-initial-globals

Conversation

@lifeiscontent

@lifeiscontent lifeiscontent commented Jun 18, 2026 •

Copy link
Copy Markdown
Member

Note

Stacked on #35224. Until that merges this PR also shows its portable-stories commit; review only the Addon-vitest: add an initialGlobals option ... commit here. Kept as a draft until #35224 lands.

What I did

Adds an initialGlobals option to storybookTest(). It's threaded into each test run via Vitest's provide/inject and merged underneath Storybook's own run-control globals (so a11y.manual and the internal keys still win). It's the per-project equivalent of initialGlobals in .storybook/preview.

The motivating use is theme testing. Once #35224 makes @storybook/addon-themes decorators apply under the test runner, you can run the a11y/interaction gate across every theme by defining one Vitest project per theme:

// vitest.config.ts
test: {
  projects: ['light', 'dark', 'light-contrast', 'dark-contrast'].map((theme) => ({
    extends: true,
    plugins: [storybookTest({ configDir: '.storybook', initialGlobals: { theme } })],
    test: { name: theme, browser: { enabled: true, provider: playwright(), instances: [{ browser: 'chromium' }] } },
  })),
}

How it works

  • UserOptions.initialGlobals (default {}).
  • storybookTest() provides it under a new key in test.provide.
  • testStory() injects it and spreads it first into the composed story's initialGlobals, so the addon's own globals override it.

Open questions

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for configuring project-wide Storybook globals in Vitest. Users can now pin toolbar values (such as theme) across test runs on a per-Vitest-project basis, complementing global .storybook/preview settings.
  • Tests

    • Added comprehensive test suite for globals composition logic.

@lifeiscontent
lifeiscontent force-pushed the lifeiscontent/addon-vitest-initial-globals branch from 1c71eaa to ac1de14 Compare June 18, 2026 20:32
@lifeiscontent
lifeiscontent marked this pull request as ready for review June 18, 2026 20:33
Copilot AI review requested due to automatic review settings June 18, 2026 20:33
@coderabbitai

coderabbitai Bot commented Jun 18, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The Vitest addon gains a new initialGlobals plugin option. A STORYBOOK_TEST_INITIAL_GLOBALS_PROVIDE_KEY constant is defined and registered in ProvidedContext. The plugin injects finalOptions.initialGlobals under that key via baseConfig.test.provide. A new composeInitialGlobals helper merges user-provided globals with Storybook run-control globals, and testStory in test-utils.ts is updated to use it.

Changes

Vitest plugin initialGlobals support

Layer / File(s) Summary
UserOptions type and provide-key constant
code/addons/vitest/src/vitest-plugin/types.ts, code/addons/vitest/src/constants.ts, code/addons/vitest/src/vitest-provided-context.d.ts
initialGlobals?: Record<string, unknown> added to UserOptions; STORYBOOK_TEST_INITIAL_GLOBALS_PROVIDE_KEY constant defined; ProvidedContext augmented with the new key typed as Record<string, unknown>.
composeInitialGlobals helper and tests
code/addons/vitest/src/vitest-plugin/compose-initial-globals.ts, code/addons/vitest/src/vitest-plugin/compose-initial-globals.test.ts
composeInitialGlobals merges userInitialGlobals with Storybook run-control globals (a11y, ghostStories, renderAnalysis), injecting runConfig under STORYBOOK_TEST_PROVIDE_KEY and ensuring run-control values override user values. Tests cover user value propagation, override precedence, and conditional feature-flag behavior.
Plugin injection into Vite test provide map
code/addons/vitest/src/vitest-plugin/index.ts
Imports STORYBOOK_TEST_INITIAL_GLOBALS_PROVIDE_KEY, adds initialGlobals: {} to defaultOptions, and maps finalOptions.initialGlobals into baseConfig.test.provide under the new key.
testStory globals merge in test-utils
code/addons/vitest/src/vitest-plugin/test-utils.ts
Reads the injected value via inject(STORYBOOK_TEST_INITIAL_GLOBALS_PROVIDE_KEY) with a try/catch fallback to {}, then delegates to composeInitialGlobals to build the final globals for each story execution.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for pinning Storybook globals per Vitest project in @storybook/addon-vitest, enabling workflows like “one theme per project” runs by threading initialGlobals through Vitest’s provide/inject and merging it beneath Storybook’s internal run-control globals.

Changes:

  • Add UserOptions.initialGlobals to storybookTest() and provide it into Vitest’s project context.
  • Inject initialGlobals during testStory() composition and merge it under Storybook’s internal globals (e.g. a11y.manual).
  • (Stacked) Update portable stories to flush preview-api hook effects after render, with a regression test.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
code/renderers/react/src/test/portable-stories.test.tsx Adds a regression test ensuring preview-api useEffect decorator side-effects are flushed under portable stories.
code/core/src/preview-api/modules/store/csf/portable-stories.ts Flushes preview-api hook effects in the portable render path by invoking the hooks render listener post-render.
code/addons/vitest/src/vitest-plugin/types.ts Introduces the public initialGlobals option on the vitest addon plugin options.
code/addons/vitest/src/vitest-plugin/test-utils.ts Injects project initialGlobals and merges them into the composed story’s globals for each run.
code/addons/vitest/src/vitest-plugin/index.ts Provides initialGlobals via Vitest test.provide for the project.
code/addons/vitest/src/constants.ts Adds a new provide/inject key constant for initialGlobals.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread code/addons/vitest/src/constants.ts
Comment thread code/addons/vitest/src/vitest-plugin/test-utils.ts
@lifeiscontent
lifeiscontent force-pushed the lifeiscontent/addon-vitest-initial-globals branch from ac1de14 to d2f7b94 Compare June 18, 2026 20:46
@lifeiscontent lifeiscontent changed the title Addon-vitest: add an initialGlobals option to pin a project's globals Addon-vitest: Add an initialGlobals option to pin a project's globals Jun 18, 2026
@lifeiscontent lifeiscontent added feature request ci:normal Run our default set of CI jobs (choose this for most PRs). qa:needed Pull Requests that will need manual QA prior to release. labels Jun 18, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
code/addons/vitest/src/vitest-plugin/compose-initial-globals.test.ts (1)

19-43: ⚡ Quick win

Add regression cases for disabled-flag precedence and partial a11y override.

Current tests don’t cover the case where ghostStoriesEnabled/renderAnalysisEnabled are false and userInitialGlobals tries to set them to enabled. Add that assertion to lock the precedence contract. Also add a case ensuring only a11y.manual is overridden (and other a11y keys are preserved), if that is the intended behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@code/addons/vitest/src/vitest-plugin/compose-initial-globals.test.ts` around
lines 19 - 43, The test file needs additional regression cases for the
composeInitialGlobals function. Add a test that verifies when
ghostStoriesEnabled or renderAnalysisEnabled are explicitly set to false, the
function prevents userInitialGlobals from overriding those disabled flags to
enabled (testing the precedence contract). Additionally, add a test case that
provides a partial a11y override in userInitialGlobals (for example, only
overriding a11y.manual while leaving other a11y properties) to ensure only the
specified a11y properties are overridden and any other existing a11y keys are
preserved from the base or run configuration.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@code/addons/vitest/src/vitest-plugin/compose-initial-globals.ts`:
- Line 26: The a11y field assignment on line 26 is replacing the entire a11y
object with only the manual property, discarding any other user-provided a11y
configuration. Instead of assigning a new object with just the manual field,
merge the manual property into the existing a11y configuration to preserve any
other user-defined a11y globals. Use object spreading or a merge operation to
combine the user's a11y configuration with the computed manual property so that
manual takes precedence while other user fields remain intact.
- Around line 24-25: The conditional spreading of ghostStories and
renderAnalysis globals allows them to be bypassed if userInitialGlobals already
contains these properties. Instead of conditionally spreading these objects only
when enabled, set them unconditionally in the globals object with their
respective enabled flags (ghostStoriesEnabled and renderAnalysisEnabled) so that
the run-control flags always take precedence over any values in
userInitialGlobals.

---

Nitpick comments:
In `@code/addons/vitest/src/vitest-plugin/compose-initial-globals.test.ts`:
- Around line 19-43: The test file needs additional regression cases for the
composeInitialGlobals function. Add a test that verifies when
ghostStoriesEnabled or renderAnalysisEnabled are explicitly set to false, the
function prevents userInitialGlobals from overriding those disabled flags to
enabled (testing the precedence contract). Additionally, add a test case that
provides a partial a11y override in userInitialGlobals (for example, only
overriding a11y.manual while leaving other a11y properties) to ensure only the
specified a11y properties are overridden and any other existing a11y keys are
preserved from the base or run configuration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 06f9d2ec-ba2c-4cd5-9339-e3abbd3b4394

📥 Commits

Reviewing files that changed from the base of the PR and between ac1de14 and d2f7b94.

📒 Files selected for processing (9)
  • code/addons/vitest/src/constants.ts
  • code/addons/vitest/src/vitest-plugin/compose-initial-globals.test.ts
  • code/addons/vitest/src/vitest-plugin/compose-initial-globals.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/addons/vitest/src/vitest-plugin/test-utils.ts
  • code/addons/vitest/src/vitest-plugin/types.ts
  • code/addons/vitest/src/vitest-provided-context.d.ts
  • code/core/src/preview-api/modules/store/csf/portable-stories.ts
  • code/renderers/react/src/__test__/portable-stories.test.tsx
✅ Files skipped from review due to trivial changes (2)
  • code/addons/vitest/src/vitest-provided-context.d.ts
  • code/addons/vitest/src/constants.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • code/addons/vitest/src/vitest-plugin/types.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/addons/vitest/src/vitest-plugin/test-utils.ts
  • code/core/src/preview-api/modules/store/csf/portable-stories.ts
  • code/renderers/react/src/test/portable-stories.test.tsx

Comment thread code/addons/vitest/src/vitest-plugin/compose-initial-globals.ts Outdated
Comment thread code/addons/vitest/src/vitest-plugin/compose-initial-globals.ts Outdated
@lifeiscontent
lifeiscontent force-pushed the lifeiscontent/addon-vitest-initial-globals branch 5 times, most recently from a6ac4b6 to f011f2b Compare June 19, 2026 06:29
@Sidnioulz
Sidnioulz force-pushed the lifeiscontent/addon-vitest-initial-globals branch from f011f2b to b64233b Compare June 19, 2026 07:13
@Sidnioulz

Sidnioulz commented Jun 19, 2026 •

Copy link
Copy Markdown
Contributor

@lifeiscontent looks good to me codewise, though we'll need documentation for this new feature. Would you like to give this a go?

As for testing, you could add an initialGlobals: { initialGlobalsWork: true } to the monorepo config and then print out that global value in a story and assert the output in a play function.

@lifeiscontent

Copy link
Copy Markdown
Member Author

@Sidnioulz sounds good, I'll try putting it together tomorrow 🙌

@lifeiscontent
lifeiscontent force-pushed the lifeiscontent/addon-vitest-initial-globals branch from b64233b to 83ae1d6 Compare June 20, 2026 15:30
@lifeiscontent

Copy link
Copy Markdown
Member Author

Done on both fronts:

  • Docs: added an initialGlobals entry under the plugin options, with a snippet showing the one-project-per-theme setup as the main use case.
  • Test: pinned initialGlobals: { initialGlobalsWork: true } in vitest.config.storybook.ts and added an InitialGlobals story that renders the global and asserts it in a play function. I put it in addons/vitest/src/components rather than a template story on purpose, since the global only comes from the monorepo config and sandbox runs would not have it.

@lifeiscontent
lifeiscontent force-pushed the lifeiscontent/addon-vitest-initial-globals branch from 83ae1d6 to 70a362e Compare June 20, 2026 20:59
This was referenced Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:normal Run our default set of CI jobs (choose this for most PRs). feature request qa:success Pull Requests that were successfully QA'ed by the release team.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants