Skip to content

Comments

Addon-Vitest: Add channel API to programmatically trigger test runs#33206

Merged
JReinhold merged 29 commits intonextfrom
jeppe/addon-vitest-trigger-api
Feb 19, 2026
Merged

Addon-Vitest: Add channel API to programmatically trigger test runs#33206
JReinhold merged 29 commits intonextfrom
jeppe/addon-vitest-trigger-api

Conversation

@JReinhold
Copy link
Contributor

@JReinhold JReinhold commented Nov 27, 2025

Works on storybookjs/mcp#138

Companion PR: storybookjs/mcp#131

What I did

Added a new programmatic trigger to addon-vitest, which allows external actors (like addon-mcp) to trigger a test run and get results back via events on the channel.

To support this, I had to make additional modifications:

  1. Add the channel to the options, so that any preset property (like experimental_devServer) automatically has access to the channel and can do stuff with it.
  2. Replaced the flow for how addon-vitest gets the index on the server.

Previously, it would fetch the index.json when necessary; however, it wouldn't know which origin/url to fetch from. To know that, the manager would send the origin to the server (indexUrl) on startup, because the client does know where to fetch the index from. If this sounds bad, it's because it was, but it was a good compromise at the time.

But not anymore, because now you can trigger tests without even opening the manager UI once, which would leave indexUrl undefined, and crash the test run. So now it does the more clear thing, which is possible as of recently, but wasn't before. Now addon-vitest gets the index directly from StoryIndexGenerator on the server, and subscribes to changes to the index, so that when tests are triggered, the index is already available and up-to-date.

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

  1. Have a react-vite Storybook with addon-mcp installed from Add testing toolset mcp#131
  2. Start the dev server and configure the MCP server for your agent
  3. Prompt your agent with "Run tests for the Button component stories using the Storybook MCP testing tool. Use the run-story-tests tool and report which stories passed or failed."
  4. See that it runs tests and reports results back. See that in the Storybook UI, you can see the statuses too in the sidebar/testing widget, because they are all connected.

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This pull request has been released as version 0.0.0-pr-33206-sha-06900f2a. Try it out in a new sandbox by running npx storybook@0.0.0-pr-33206-sha-06900f2a sandbox or in an existing project with npx storybook@0.0.0-pr-33206-sha-06900f2a upgrade.

More information
Published version 0.0.0-pr-33206-sha-06900f2a
Triggered by @JReinhold
Repository storybookjs/storybook
Branch jeppe/addon-vitest-trigger-api
Commit 06900f2a
Datetime Fri Feb 6 12:53:21 UTC 2026 (1770382401)
Workflow run 21751255283

To request a new release of this pull request, mention the @storybookjs/core team.

core team members can create a new canary release here or locally with gh workflow run --repo storybookjs/storybook publish.yml --field pr=33206

Summary by CodeRabbit

  • New Features

    • Programmatic Vitest test-run API with trigger/response flow, optional config override, and new run/result types
    • A11y addon exposes an opt-in preset and a runtime flag; per-run a11y statuses and reports are surfaced
    • In-memory story index for faster lookup and focused-run filtering
  • Refactor

    • Standardized accessibility type names
    • Streamlined channel plumbing across server, build, and presets
  • Tests

    • New tests for selective/focused test triggering and result handling

@nx-cloud
Copy link

nx-cloud bot commented Nov 27, 2025

View your CI Pipeline Execution ↗ for commit a3aad16

Command Status Duration Result
nx run-many -t compile,check,knip,test,pretty-d... ❌ Failed 1m 6s View ↗

☁️ Nx Cloud last updated this comment at 2026-02-19 19:14:14 UTC

@storybook-bot
Copy link
Contributor

Failed to publish canary version of this pull request, triggered by @JReinhold. See the failed workflow run at: https://github.com/storybookjs/storybook/actions/runs/19732250010

@storybook-bot
Copy link
Contributor

Failed to publish canary version of this pull request, triggered by @JReinhold. See the failed workflow run at: https://github.com/storybookjs/storybook/actions/runs/21150762531

@storybook-bot
Copy link
Contributor

Failed to publish canary version of this pull request, triggered by @JReinhold. See the failed workflow run at: https://github.com/storybookjs/storybook/actions/runs/21150973271

@storybook-bot
Copy link
Contributor

Failed to publish canary version of this pull request, triggered by @JReinhold. See the failed workflow run at: https://github.com/storybookjs/storybook/actions/runs/21151373423

@JReinhold JReinhold changed the title WIP: Addon-Vitest: Add test trigger API, take screenshots WIP: Addon-Vitest: Add channel API to programmatically trigger test runs Jan 20, 2026
@JReinhold JReinhold changed the title WIP: Addon-Vitest: Add channel API to programmatically trigger test runs Addon-Vitest: Add channel API to programmatically trigger test runs Feb 17, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 17, 2026

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

Adds an a11y preset/export and renames A11YReport → A11yReport; exposes isAddonA11yEnabled; introduces TRIGGER_TEST_RUN channel APIs for the Vitest addon, switches Vitest to an in-memory StoryIndex with invalidation, threads a Channel through preset loading and dev/build server flows.

Changes

Cohort / File(s) Summary
A11y addon preset & exports
code/addons/a11y/build-config.ts, code/addons/a11y/package.json, code/addons/a11y/preset.js, code/addons/a11y/src/preset.ts, code/addons/a11y/src/index.ts
Add ./preset build/export and package export, re-export dist/preset.js, and export isAddonA11yEnabled.
A11y type rename
code/addons/a11y/src/types.ts, code/addons/a11y/src/components/A11yContext.tsx
Rename exported type A11YReportA11yReport and update imports/usages.
Vitest constants & exports
code/addons/vitest/build-config.ts, code/addons/vitest/package.json, code/addons/vitest/src/constants.ts
Add ./constants export and new channel constants TRIGGER_TEST_RUN_REQUEST/RESPONSE and related payload/result types; adjust initial store shape.
Vitest types / CurrentRun / StoreState
code/addons/vitest/src/types.ts
Introduce A11yReport alias, new CurrentRun type, replace indexUrl with index: StoryIndex, add configOverride to trigger payloads, extend RunTrigger and enrich VitestError.
Vitest run flow / test-manager
code/addons/vitest/src/node/test-manager.ts, code/addons/vitest/src/manager.tsx
Propagate configOverride into runs; consolidate batching to compute/store componentTestStatuses, a11yStatuses, a11yReports; filter results to requested stories; remove prior store-readiness gating for listener registration.
Vitest story-index integration & preset
code/addons/vitest/src/node/vitest-manager.ts, code/addons/vitest/src/preset.ts
Replace network fetch of story index with in-memory store.index; seed/refresh index via StoryIndexGenerator (onInvalidated); add TRIGGER_TEST_RUN request/response handling on the channel, including configOverride handling.
Core: Channel threading & dev-server changes
code/core/src/cli/buildIndex.ts, code/core/src/common/presets.ts, code/core/src/core-server/build-dev.ts, code/core/src/core-server/build-static.ts, code/core/src/core-server/load.ts, code/core/src/core-server/dev-server.ts
Thread Channel into preset loading and build/dev init, change storybookDevServer signature to accept server, and source channel from options rather than server-channel helper.
Core types & index-json rename
code/core/src/types/modules/core-common.ts, code/core/src/core-server/utils/index-json.ts, code/core/src/core-server/utils/index-json.test.ts
Remove ServerChannel interface, add channel: ChannelLike to public options/Builder signatures, and rename serverChannel parameter to channel in index-json route and tests.
Builders & tests: pass Channel / index mocks
code/builders/builder-vite/src/vite-config.test.ts, code/frameworks/angular/src/builders/*, code/frameworks/angular/src/server/framework-preset-angular-cli.test.ts, code/addons/vitest/src/node/test-manager.test.ts
Add Channel imports/instances in tests and builder preset options; update vitest tests to use an in-memory index mock instead of fetch/channel transport mocks.
Channels typing & class changes
code/core/src/channels/types.ts, code/core/src/channels/main.ts, code/core/src/channels/index.ts
Add ChannelLike interface and async? in args, make Channel implement ChannelLike, and export ChannelLike type.
Telemetry & formatting adjustments
code/core/src/core-server/utils/doTelemetry.ts, code/core/src/core-server/utils/whats-new.ts
Reformat presetOptions passed to telemetry error helpers (styling/typing changes) and add channel wiring in telemetry call sites.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client
participant Channel
participant VitestPreset
participant TestManager
participant Store
Client->>Channel: TRIGGER_TEST_RUN_REQUEST (storyIds?, configOverride?)
Channel->>VitestPreset: deliver request
VitestPreset->>TestManager: dispatch TRIGGER_RUN (triggeredBy: external, configOverride)
TestManager->>Store: set currentRun (includes configOverride)
TestManager->>TestManager: run tests (batch, aggregate component/a11y statuses & reports)
TestManager->>Store: update componentTestStatuses / a11yStatuses / a11yReports
TestManager->>Channel: emit TRIGGER_TEST_RUN_RESPONSE (result / error)
Channel->>Client: deliver TRIGGER_TEST_RUN_RESPONSE

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs


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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (4)
code/addons/vitest/src/types.ts (1)

2-2: Avoid leaking any in the public A11y report typing.
any weakens downstream type safety; consider unknown or a minimal structural type as a temporary workaround.

♻️ Suggested typing tweak
-type A11yReport = any;
+type A11yReport = unknown;

Also applies to: 5-8

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/addons/vitest/src/types.ts` at line 2, The public A11y report types leak
`any`; update those exported types (e.g., A11yReport, A11yResult or any
similarly named interfaces found in this file) to replace `any` with `unknown`
or a small structural type (e.g., { id?: string; message?: string; nodes?:
unknown[] }) so downstream code has safer typings; adjust any callsites or type
assertions to narrow/validate the unknowns as needed and export the new types in
place of the `any`-using definitions.
code/addons/vitest/src/node/test-manager.ts (1)

269-274: Verify array concatenation doesn't cause memory issues with large test suites.

The statuses are accumulated via concat() on every throttled flush. For very large test suites, this could result in significant memory growth. Consider if there's a maximum expected size or if the arrays are cleared between runs.

Looking at the code, storeOptions.initialState.currentRun is spread into currentRun at the start of each run (line 143), which should reset these arrays. This appears safe.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/addons/vitest/src/node/test-manager.ts` around lines 269 - 274, The
concatenation of componentTestStatuses, a11yStatuses and a11yReports on each
throttled flush can grow unbounded across runs; ensure these arrays are reset at
run start by using the initialized currentRun from
storeOptions.initialState.currentRun (the code path that sets state.currentRun
at run start) or explicitly clear them before concatenation in the flush code
(references: componentTestStatuses, a11yStatuses, a11yReports, currentRun,
storeOptions.initialState.currentRun); if a hard bound is needed also trim
(slice) the arrays to a configured max length before storing to avoid memory
growth for very large suites.
code/addons/vitest/src/constants.ts (1)

31-31: Consider using a constant or importing the version from StoryIndex type.

The hardcoded v: 5 could become stale if the StoryIndex version changes. Consider importing or referencing a shared constant to ensure consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/addons/vitest/src/constants.ts` at line 31, Replace the hardcoded
StoryIndex version value (currently "v: 5" in the object literal with key
`index`) with a shared constant or the exported version from the StoryIndex
type/module so it stays in sync; locate the `index: { entries: {}, v: 5 }` entry
in constants.ts and import or reference the canonical VERSION/SCHEMA_VERSION (or
StoryIndex.VERSION) and use that symbol instead of the literal 5.
code/addons/vitest/src/preset.ts (1)

28-28: Consider using public API instead of reaching into core internals.

The import '../../../core/src/node-logger/logger' directly accesses internal core modules. If shouldLog is needed, consider exporting it from storybook/internal/node-logger to maintain proper module boundaries.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/addons/vitest/src/preset.ts` at line 28, The code imports the internal
helper shouldLog from core internals; update it to use the public API by
importing shouldLog from the exported entry (e.g.,
storybook/internal/node-logger) instead of
'../../../core/src/node-logger/logger'. If that symbol isn't currently exported,
add an export of shouldLog from the public module (node-logger index or
storybook/internal/node-logger) so code in preset.ts can import shouldLog via
the public path; ensure you update the import statement in preset.ts to
reference the public module name (storybook/internal/node-logger) and remove the
direct core/src import.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@code/addons/a11y/src/types.ts`:
- Line 5: Add a deprecated compatibility alias so existing imports using the old
A11YReport name continue to work: export a new type alias A11YReport that points
to the new A11yReport (and optionally annotate it with a JSDoc `@deprecated` tag).
Update the same types file where A11yReport is defined to include this alias
(referencing the A11yReport type) so downstream code isn't broken by the rename.

In `@code/addons/vitest/src/node/vitest-manager.ts`:
- Around line 221-227: getStories may return undefined items when
requestStoryIds contains IDs not present in
this.testManager.store.getState().index.entries; change the mapping logic in
getStories to skip missing entries (e.g., map then filter out undefined or use
flatMap to only include found StoryIndexEntry) so the returned array contains
only StoryIndexEntry objects and not undefined values. Update the code path that
uses getStories to rely on the cleaned array but do not rely on the previous
cast to StoryIndexEntry[] to hide missing entries. Ensure you reference the
getStories method and the index.entries lookup when making the fix.

In `@code/addons/vitest/src/preset.ts`:
- Around line 86-88: The result of options.presets.apply('storyIndexGenerator')
(stored in storyIndexGenerator) may be null/undefined; before calling
storyIndexGenerator.getIndex(...) and storyIndexGenerator.onInvalidated(...),
add a null check (e.g., if (!storyIndexGenerator) return or skip those calls) so
you don't invoke methods on undefined; update the code paths that call getIndex
and onInvalidated (referencing storyIndexGenerator, getIndex, onInvalidated, and
options.presets.apply) to guard them and handle the absent generator case
gracefully (either no-op, log a warning, or provide a fallback).

In `@code/addons/vitest/src/types.ts`:
- Around line 69-78: The initial call to storyIndexGenerator.getIndex() should
be wrapped in the same try-catch used in the onInvalidated callback: call await
storyIndexGenerator.getIndex() inside a try block and if it throws or returns
undefined, set index to the fallback default from storeOptions.initialState
(e.g. { entries: {}, v: 5 }) and populate the store's fatalError field with the
caught error; update the store initialization logic that sets index (and
fatalError) so the rest of the store (and components reading index.entries)
never sees undefined.

---

Nitpick comments:
In `@code/addons/vitest/src/constants.ts`:
- Line 31: Replace the hardcoded StoryIndex version value (currently "v: 5" in
the object literal with key `index`) with a shared constant or the exported
version from the StoryIndex type/module so it stays in sync; locate the `index:
{ entries: {}, v: 5 }` entry in constants.ts and import or reference the
canonical VERSION/SCHEMA_VERSION (or StoryIndex.VERSION) and use that symbol
instead of the literal 5.

In `@code/addons/vitest/src/node/test-manager.ts`:
- Around line 269-274: The concatenation of componentTestStatuses, a11yStatuses
and a11yReports on each throttled flush can grow unbounded across runs; ensure
these arrays are reset at run start by using the initialized currentRun from
storeOptions.initialState.currentRun (the code path that sets state.currentRun
at run start) or explicitly clear them before concatenation in the flush code
(references: componentTestStatuses, a11yStatuses, a11yReports, currentRun,
storeOptions.initialState.currentRun); if a hard bound is needed also trim
(slice) the arrays to a configured max length before storing to avoid memory
growth for very large suites.

In `@code/addons/vitest/src/preset.ts`:
- Line 28: The code imports the internal helper shouldLog from core internals;
update it to use the public API by importing shouldLog from the exported entry
(e.g., storybook/internal/node-logger) instead of
'../../../core/src/node-logger/logger'. If that symbol isn't currently exported,
add an export of shouldLog from the public module (node-logger index or
storybook/internal/node-logger) so code in preset.ts can import shouldLog via
the public path; ensure you update the import statement in preset.ts to
reference the public module name (storybook/internal/node-logger) and remove the
direct core/src import.

In `@code/addons/vitest/src/types.ts`:
- Line 2: The public A11y report types leak `any`; update those exported types
(e.g., A11yReport, A11yResult or any similarly named interfaces found in this
file) to replace `any` with `unknown` or a small structural type (e.g., { id?:
string; message?: string; nodes?: unknown[] }) so downstream code has safer
typings; adjust any callsites or type assertions to narrow/validate the unknowns
as needed and export the new types in place of the `any`-using definitions.

@storybook-app-bot
Copy link

storybook-app-bot bot commented Feb 17, 2026

Package Benchmarks

Commit: a3aad16, ran on 19 February 2026 at 19:23:08 UTC

The following packages have significant changes to their size or dependencies:

@storybook/addon-vitest

Before After Difference
Dependency count 2 2 0
Self size 391 KB 402 KB 🚨 +12 KB 🚨
Dependency size 338 KB 338 KB 0 B
Bundle Size Analyzer Link Link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
code/addons/vitest/src/node/test-manager.test.ts (2)

185-185: Consider moving mock implementations to beforeEach block.

The globTestSpecifications mock implementation appears inline in multiple test cases (lines 185, 200, 215, 230, 247):

vitest.globTestSpecifications.mockImplementation(() => tests);

Per coding guidelines, mock implementations should be in beforeEach blocks rather than inline within test cases. Consider adding this to a shared beforeEach:

♻️ Suggested refactor
 beforeEach(() => {
   createVitest.mockResolvedValue(vitest);
+  vitest.globTestSpecifications.mockImplementation(() => tests);
 });

Then remove the inline mockImplementation calls from individual tests.

Based on learnings: "Implement mock behaviors in beforeEach blocks in Vitest tests" and "Avoid inline mock implementations within test cases in Vitest tests."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/addons/vitest/src/node/test-manager.test.ts` at line 185, Move the
repeated inline mock setup for vitest.globTestSpecifications into a shared
beforeEach so tests reuse the same mock behavior: add a beforeEach that calls
vitest.globTestSpecifications.mockImplementation(() => tests) (or equivalent
using the existing tests variable) and remove the individual inline
mockImplementation calls from the tests; ensure any tests that need a different
behavior override the mock inside their own test or a nested describe, and keep
the symbol references vitest.globTestSpecifications, beforeEach, and tests to
locate and update the code.

127-135: Consider moving mock implementation to beforeEach.

The runWithState mock has its implementation defined at module scope:

runWithState: vi.fn((callback) => callback()),

Per coding guidelines, mock implementations should be in beforeEach blocks. Consider:

♻️ Suggested refactor
 const mockTestProviderStore: TestProviderStoreById = {
   getState: vi.fn(),
   setState: vi.fn(),
   settingsChanged: vi.fn(),
   onRunAll: vi.fn(),
   onClearAll: vi.fn(),
-  runWithState: vi.fn((callback) => callback()),
+  runWithState: vi.fn(),
   testProviderId: 'test-provider-id',
 };

Then in beforeEach:

beforeEach(() => {
  createVitest.mockResolvedValue(vitest);
  vi.mocked(mockTestProviderStore.runWithState).mockImplementation((callback) => callback());
});

Based on learnings: "Avoid mock implementations outside of beforeEach blocks in Vitest tests."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/addons/vitest/src/node/test-manager.test.ts` around lines 127 - 135, The
mock implementation for runWithState is defined at module scope on
mockTestProviderStore; move that implementation into a beforeEach so mocks are
reset per-test. Remove the inline vi.fn((callback) => callback()) from
mockTestProviderStore and in the beforeEach set
vi.mocked(mockTestProviderStore.runWithState).mockImplementation((callback) =>
callback()); also ensure any related setup such as
createVitest.mockResolvedValue(vitest) is configured in the same beforeEach so
all test-scoped mocks are initialized there.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@code/addons/vitest/src/node/test-manager.test.ts`:
- Line 185: Move the repeated inline mock setup for
vitest.globTestSpecifications into a shared beforeEach so tests reuse the same
mock behavior: add a beforeEach that calls
vitest.globTestSpecifications.mockImplementation(() => tests) (or equivalent
using the existing tests variable) and remove the individual inline
mockImplementation calls from the tests; ensure any tests that need a different
behavior override the mock inside their own test or a nested describe, and keep
the symbol references vitest.globTestSpecifications, beforeEach, and tests to
locate and update the code.
- Around line 127-135: The mock implementation for runWithState is defined at
module scope on mockTestProviderStore; move that implementation into a
beforeEach so mocks are reset per-test. Remove the inline vi.fn((callback) =>
callback()) from mockTestProviderStore and in the beforeEach set
vi.mocked(mockTestProviderStore.runWithState).mockImplementation((callback) =>
callback()); also ensure any related setup such as
createVitest.mockResolvedValue(vitest) is configured in the same beforeEach so
all test-scoped mocks are initialized there.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
code/core/src/core-server/build-dev.ts (1)

160-160: Avoid as unknown as casts; align channel types.

The double-casts at lines 160, 218, and 229 weaken type safety. getServerChannel returns a Channel instance that TypeScript cannot directly align with the type expected by loadAllPresets's channel parameter and Options['channel']. Consider updating getServerChannel's return type to match the expected channel type used by loadAllPresets, or introduce a shared Channel type alias to eliminate the unknown intermediate cast.

This pattern also appears in load.ts and build-static.ts.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/core-server/build-dev.ts` at line 160, The double-cast using
"as unknown as" for channel should be removed by aligning types: update
getServerChannel's return type to the Channel type expected by loadAllPresets
(the same type used in Options['channel']), or introduce a shared Channel type
alias and use that everywhere; then replace occurrences like "channel as unknown
as Parameters<typeof loadAllPresets>[0]['channel']" (in build-dev.ts, load.ts,
build-static.ts) with a direct typed value so no unknown intermediate cast is
needed. Ensure function signatures (getServerChannel) and variable declarations
import/use the shared Channel type so callers (loadAllPresets and any
Options['channel'] consumers) accept the returned type without casting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@code/core/src/core-server/build-dev.ts`:
- Line 160: The double-cast using "as unknown as" for channel should be removed
by aligning types: update getServerChannel's return type to the Channel type
expected by loadAllPresets (the same type used in Options['channel']), or
introduce a shared Channel type alias and use that everywhere; then replace
occurrences like "channel as unknown as Parameters<typeof
loadAllPresets>[0]['channel']" (in build-dev.ts, load.ts, build-static.ts) with
a direct typed value so no unknown intermediate cast is needed. Ensure function
signatures (getServerChannel) and variable declarations import/use the shared
Channel type so callers (loadAllPresets and any Options['channel'] consumers)
accept the returned type without casting.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
code/addons/vitest/src/node/vitest-manager.ts (1)

257-264: Consider graceful handling when parent story is missing.

If the index has a stale or inconsistent parent reference, this throws at runtime and aborts the test run. Consider either skipping the story with a warning or using a fallback pattern.

💡 Alternative: fallback to simple pattern
     if (story.parent) {
       const parentStory = storiesById[story.parent];
       if (!parentStory) {
-        throw new Error(`Parent story not found for story ${story.id}`);
+        // Fallback if parent reference is stale; match just the child name
+        return `^${escapeRegExp(story.name)}$`;
       }
 
       return `^${escapeRegExp(getTestName(parentStory.name))} ${escapeRegExp(story.name)}$`;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/addons/vitest/src/node/vitest-manager.ts` around lines 257 - 264, The
current block in vitest-manager.ts throws when a story's parent id is missing
(uses story.parent and looks up storiesById), which can abort test runs; change
this to handle missing parent gracefully by either logging a warning via the
existing logger and returning a fallback pattern (e.g., use only
escapeRegExp(getTestName(story.name)) or a looser regex) or by skipping the
story with a warning instead of throwing; update the branch that calls
getTestName(parentStory.name) and escapeRegExp so it checks for parentStory
presence and uses the chosen fallback (or skip) to avoid runtime errors when
storiesById lacks the parent.
code/addons/vitest/src/node/test-manager.test.ts (1)

47-50: Missing spy: true option in vi.mock call.

As per coding guidelines, all vi.mock() calls should use the spy: true option for consistent mocking patterns.

♻️ Proposed fix
-vi.mock('vitest/node', async (importOriginal) => ({
+vi.mock('vitest/node', { spy: true }, async (importOriginal) => ({
   ...(await importOriginal()),
   createVitest: mockCreateVitest,
 }));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/addons/vitest/src/node/test-manager.test.ts` around lines 47 - 50, The
vi.mock call that replaces createVitest with mockCreateVitest must include the
spy: true option; update the vi.mock invocation for 'vitest/node' (the one that
returns ...(await importOriginal()) and createVitest: mockCreateVitest) to pass
the third argument { spy: true } so the mock is created with spying enabled.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@code/addons/vitest/src/node/test-manager.test.ts`:
- Around line 47-50: The vi.mock call that replaces createVitest with
mockCreateVitest must include the spy: true option; update the vi.mock
invocation for 'vitest/node' (the one that returns ...(await importOriginal())
and createVitest: mockCreateVitest) to pass the third argument { spy: true } so
the mock is created with spying enabled.

In `@code/addons/vitest/src/node/vitest-manager.ts`:
- Around line 257-264: The current block in vitest-manager.ts throws when a
story's parent id is missing (uses story.parent and looks up storiesById), which
can abort test runs; change this to handle missing parent gracefully by either
logging a warning via the existing logger and returning a fallback pattern
(e.g., use only escapeRegExp(getTestName(story.name)) or a looser regex) or by
skipping the story with a warning instead of throwing; update the branch that
calls getTestName(parentStory.name) and escapeRegExp so it checks for
parentStory presence and uses the chosen fallback (or skip) to avoid runtime
errors when storiesById lacks the parent.

@kasperpeulen kasperpeulen force-pushed the jeppe/addon-vitest-trigger-api branch from 1ffe647 to aaa7410 Compare February 19, 2026 12:18
The Channel class has a private `sender` field which causes TypeScript
nominal incompatibility between source and dist declarations. This
introduces a ChannelLike structural interface and uses it in Options,
loadAllPresets, and Builder types, eliminating all `as unknown as`
channel casts.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
code/core/src/core-server/utils/index-json.ts (1)

11-11: Consider reordering imports for consistency.

The ChannelLike import from storybook/internal/channels should be grouped with other storybook/internal/* imports (lines 4-5) rather than placed after local imports.

Suggested reordering
 import { STORY_INDEX_INVALIDATED } from 'storybook/internal/core-events';
 import type { NormalizedStoriesSpecifier } from 'storybook/internal/types';
+import type { ChannelLike } from 'storybook/internal/channels';
 
 import { debounce } from 'es-toolkit/function';
 import type { Polka } from 'polka';
 
 import type { StoryIndexGenerator } from './StoryIndexGenerator';
-import type { ChannelLike } from 'storybook/internal/channels';
 import { watchStorySpecifiers } from './watch-story-specifiers';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/core-server/utils/index-json.ts` at line 11, Move the
ChannelLike import so it is grouped with the other storybook internal imports
for consistency: locate the import "ChannelLike" from
'storybook/internal/channels' and reposition it alongside the existing
'storybook/internal/*' imports (the ones near the top that import Storybook
internals) rather than after local imports; ensure import ordering follows the
project's import-grouping convention (external libs, storybook internals
together, then local modules).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@code/core/src/core-server/utils/index-json.ts`:
- Line 11: Move the ChannelLike import so it is grouped with the other storybook
internal imports for consistency: locate the import "ChannelLike" from
'storybook/internal/channels' and reposition it alongside the existing
'storybook/internal/*' imports (the ones near the top that import Storybook
internals) rather than after local imports; ensure import ordering follows the
project's import-grouping convention (external libs, storybook internals
together, then local modules).

Copy link
Contributor

@kasperpeulen kasperpeulen left a comment

Choose a reason for hiding this comment

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

LGTM! Seems like some good architecture changes, couple of comments, and I fixed the channel TS issues

kasperpeulen and others added 4 commits February 19, 2026 20:26
…cy between: ws token -> server channel -> loading all presets -> core preset creates ws token -> ...

Co-authored-by: Norbert de Langen <norbert@chromatic.com>
@JReinhold JReinhold merged commit 6b05884 into next Feb 19, 2026
121 of 124 checks passed
@JReinhold JReinhold deleted the jeppe/addon-vitest-trigger-api branch February 19, 2026 19:44
@JReinhold JReinhold restored the jeppe/addon-vitest-trigger-api branch February 20, 2026 08:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants