Skip to content

Conversation

@yannbf
Copy link
Member

@yannbf yannbf commented Jan 8, 2026

Closes #

What I did

AI summary for now, I will write this properly soon

This pull request introduces the foundation for "Ghost Stories," an experimental feature for automated story discovery and testing, primarily targeting React projects using the Vitest addon. The changes add a new event-driven channel for orchestrating story discovery and testing, update the test plugin logic to support this flow, and introduce error categorization utilities with comprehensive tests. Additionally, new core events and wiring are added to support the feature.

Ghost Stories feature integration:

  • Added a new ghost-stories-channel (initGhostStoriesChannel) that listens for GHOST_STORIES_REQUEST events, discovers component candidates, runs tests on generated stories, records telemetry, and emits a response event. This is currently gated to React projects with the Vitest addon. (code/core/src/core-server/server-channel/ghost-stories-channel.ts)
  • Registered the new Ghost Stories channel in the server initialization logic, ensuring it is set up alongside other server channels. (code/core/src/core-server/presets/common-preset.ts) [1] [2]

Core events and plugin wiring:

  • Added new core events: GHOST_STORIES_REQUEST and GHOST_STORIES_RESPONSE, and exported them for use in the system. (code/core/src/core-events/index.ts) [1] [2]
  • Updated the Vitest plugin to recognize when Ghost Stories is enabled via environment variables, and to set a ghostStories global. This disables certain tests when Ghost Stories are running and ensures only relevant files are transformed. (code/addons/vitest/src/vitest-plugin/index.ts, code/addons/a11y/src/preview.tsx) [1] [2] [3] [4]

Error analysis utilities:

  • Added a utility and comprehensive test suite for categorizing and aggregating errors from automated story tests, enabling better diagnostics and telemetry for common provider and render errors. (code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts)

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

Caution

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

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-33490-sha-0cda5ae0. Try it out in a new sandbox by running npx [email protected] sandbox or in an existing project with npx [email protected] upgrade.

More information
Published version 0.0.0-pr-33490-sha-0cda5ae0
Triggered by @yannbf
Repository storybookjs/storybook
Branch yann/ghost-stories-flow
Commit 0cda5ae0
Datetime Thu Jan 8 22:43:15 UTC 2026 (1767912195)
Workflow run 20834295679

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=33490

Summary by CodeRabbit

  • New Features

    • Ghost Stories: automated component discovery, test runs, and a discovery channel for React + Vitest projects
    • In-preview empty-render detection and story-level test reporting
  • Improvements

    • Smarter candidate selection via component complexity analysis
    • Vitest integration now reads component paths from environment
    • Telemetry enriched with known-package ecosystem analysis
  • Tests

    • Extensive new tests covering Ghost Stories flows, error categorization, candidate selection, and telemetry utilities

✏️ Tip: You can customize this high-level summary in your review settings.

@nx-cloud
Copy link

nx-cloud bot commented Jan 8, 2026

View your CI Pipeline Execution ↗ for commit 340ecec

Command Status Duration Result
nx run-many -t compile,check,knip,test,pretty-d... ✅ Succeeded 10m 45s View ↗

☁️ Nx Cloud last updated this comment at 2026-01-09 12:05:48 UTC

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds a Ghost Stories feature: new core events and server channel that discover components, run Vitest on story components, categorize render errors, produce telemetry (including knownPackages), annotate previews for empty renders, and wire manager/UI and addon behaviors to trigger and respect ghost-stories mode.

Changes

Cohort / File(s) Change Summary
Core events & manager exports
code/core/src/core-events/index.ts, code/core/src/manager/globals/exports.ts
Add GHOST_STORIES_REQUEST / GHOST_STORIES_RESPONSE event identifiers and export them.
Server channel & presets
code/core/src/core-server/server-channel/ghost-stories-channel.ts, code/core/src/core-server/server-channel/ghost-stories-channel.test.ts, code/core/src/core-server/presets/common-preset.ts
New initGhostStoriesChannel implementing request handling, telemetry/cache guards, candidate discovery, Vitest orchestration, telemetry emission; comprehensive tests; wired into server presets.
Ghost-stories utilities — discovery & complexity
code/core/src/core-server/utils/ghost-stories/get-candidates.ts, .../get-candidates.test.ts, .../component-analyzer.ts, .../component-analyzer.test.ts
Add glob-based discovery, isValidCandidate, getComponentComplexity, getCandidatesForStorybook/getComponentCandidates, and tests for selection, filtering, complexity sampling.
Ghost-stories utilities — test runner & error categorization
code/core/src/core-server/utils/ghost-stories/run-story-tests.ts, .../categorize-render-errors.ts, .../categorize-render-errors.test.ts, .../types.ts
Add runStoryTests to execute Vitest and produce structured response payload; implement rule-based error categorization, aggregation utilities, types, and tests.
Preview annotations & core integration
code/core/src/core-server/utils/ghost-stories/test-annotations.ts, code/core/src/csf/core-annotations.ts
Preview addon that detects empty renders when globals.ghostStories is true; added into core annotations.
Manager UI trigger
code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx
Emit GHOST_STORIES_REQUEST once when the modal opens for React renderer (one-time guard).
Addons & Vitest plugin
code/addons/a11y/src/preview.tsx, code/addons/vitest/src/vitest-plugin/index.ts
a11y preview: add isGhostStories flag from globals and skip environment-independent a11y runs when true. Vitest plugin: change getComponentTestPaths() to read STORYBOOK_COMPONENT_PATHS from env (no vitestRoot arg), precompute paths, and set ghostStories.enabled in globals when env var present.
Telemetry & ecosystem analysis
code/core/src/telemetry/index.ts, code/core/src/telemetry/types.ts, code/core/src/telemetry/ecosystem-identifier.ts, code/core/src/telemetry/get-known-packages.ts, tests...
Add early-return handling for ghost-stories telemetry events; add package classification utilities and analyzeEcosystemPackages returning knownPackages; telemetry metadata now includes knownPackages (replace prior testPackages). Tests updated/added.

Sequence Diagram(s)

sequenceDiagram
    participant Manager as Manager/UI
    participant Channel as Ghost Stories Channel
    participant Metadata as Storybook Metadata
    participant Candidates as Candidate Discovery
    participant Vitest as Vitest Runner
    participant Telemetry as Telemetry/Cache

    Manager->>Channel: GHOST_STORIES_REQUEST
    activate Channel
    Channel->>Telemetry: check telemetry enabled & cache has-run
    alt skip (disabled or already run)
        Channel->>Manager: GHOST_STORIES_RESPONSE (skipped)
    else proceed
        Channel->>Metadata: fetch metadata (renderer, addons, knownPackages)
        alt invalid env (non-React or missing Vitest)
            Channel->>Telemetry: emit error telemetry
            Channel->>Manager: GHOST_STORIES_RESPONSE (error)
        else valid env
            Channel->>Telemetry: mark as run in cache
            Channel->>Candidates: get component candidates (glob + complexity)
            Candidates-->>Channel: component file paths
            Channel->>Vitest: run tests (npx vitest -> JSON output)
            Vitest-->>Channel: test results JSON
            Channel->>Channel: categorize errors & compute metrics
            Channel->>Telemetry: emit results telemetry (ghost-stories)
            Channel->>Manager: GHOST_STORIES_RESPONSE (payload)
        end
    end
    deactivate Channel
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fabaa0d and 340ecec.

📒 Files selected for processing (4)
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/telemetry/index.ts

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: 9

🤖 Fix all issues with AI agents
In @code/core/src/core-server/server-channel/ghost-stories-channel.test.ts:
- Around line 287-291: The expectation for uniqueErrors contains a duplicate
string 'Expected button to be disabled' inside expect.arrayContaining; remove
the duplicate entry so each expected error appears only once (update the array
in the test that references uniqueErrors/expect.arrayContaining) or
alternatively keep both but add an inline comment next to the duplicated string
explaining why the duplicate is intentional.
- Around line 32-38: The test mock targets the wrong module, so
getComponentCandidates isn't being mocked; update the vi.mock call to target the
same module that's imported in the test and use the same module type in
importOriginal, then return a mock implementation for getComponentCandidates.
Specifically, change the vi.mock target to the module that exports
getComponentCandidates, adjust the importOriginal generic to that same module,
and keep returning {...actual, getComponentCandidates: vi.fn()} so tests use the
mocked getComponentCandidates.

In @code/core/src/core-server/server-channel/ghost-stories-channel.ts:
- Around line 28-34: Restore the first-run guard by uncommenting and wiring up
the check: call getLastEvents(), read lastEvents['preview-first-load'] into
lastPreviewFirstLoad, and if truthy log via logger.debug('Skipping discovery
run', { lastEvents }) and return from the handler (symbols: getLastEvents,
lastPreviewFirstLoad, logger.debug). Ensure you handle and surface errors from
getLastEvents (don’t swallow exceptions) and add/adjust a test or local run to
verify the discovery run is skipped on repeat loads; alternatively, if the
safeguard is no longer needed, remove the entire commented block to avoid dead
code.

In @code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts:
- Around line 8-11: The test file uses vi.mock calls without the required spy
option; update each vi.mock invocation for 'node:fs/promises', 'glob',
'storybook/internal/node-logger', and './component-analyzer' to include the
option { spy: true } so the mocks follow the repository's testing guidelines;
ensure you pass the option as the second argument to vi.mock in
get-candidates.test.ts for all four mock declarations.

In @code/core/src/core-server/utils/ghost-stories/get-candidates.ts:
- Line 151: The debug log incorrectly reports "candidates files:" but prints
files.length; update the logger.debug call (the invocation of logger.debug in
get-candidates.ts) to log candidates.length (and adjust the message text if
desired) so the message reflects the actual variable being measured (candidates)
instead of files.
- Around line 150-159: The empty-files check is performed after calling
getCandidatesForStorybook, causing wasted work and potential errors; move the
files.length === 0 early-return before invoking getCandidatesForStorybook (use
the existing files and globPattern variables), log the warning via
logger.warn(`No files found matching glob pattern: ${globPattern}`) and return
the same shape ({ candidates: [], matchCount }) without calling
getCandidatesForStorybook or logger.debug; ensure callers still receive
matchCount and that getCandidatesForStorybook(files, sampleSize) is only invoked
when files.length > 0.

In @code/core/src/core-server/utils/ghost-stories/run-story-tests.ts:
- Line 163: Replace the direct console.error call with the shared logger: import
logger from 'storybook/internal/node-logger' at the top of run-story-tests.ts
and change the console.error('Error running story tests:', error) call inside
the run/story test function (the error handling block in runStoryTests or the
surrounding async function) to logger.error with a descriptive message and the
error object so it uses the centralized logging facility.

In @code/core/src/core-server/utils/ghost-stories/test-annotations.ts:
- Around line 18-38: The empty catch in the afterEach function swallows errors;
change it to catch the error (e.g., catch (err)) and log/report it instead of
doing nothing: use the existing reporting object to call reporting.addReport
with a clear type (e.g., 'internal-error' or 'annotation-error'), include
version, a message and the error details/stack (safely stringifying unknown
errors), and status (e.g., 'error'); if reporting may be undefined, fall back to
console.error with the same information so failures in ghost-stories annotation
are visible for debugging.

In @code/core/src/telemetry/index.ts:
- Around line 36-38: Remove the temporary debug early-return that logs telemetry
and short-circuits functionality: delete the console.log('telemetry ', {
eventType, payload, options }) and the following return so the telemetry
function resumes its normal flow; if any server-side logging is needed, replace
direct console calls with the shared logger (storybook/internal/node-logger) and
log contextual error/info messages instead rather than using console.log.
🧹 Nitpick comments (12)
code/core/src/core-server/utils/ghost-stories/component-analyzer.ts (3)

15-75: Be aware of edge cases in type block detection.

The heuristic approach for excluding TypeScript declarations has several known limitations:

  1. The regex patterns may match in non-declaration contexts (strings, comments, or within other identifiers).
  2. Brace counting doesn't account for braces in template literals, regex patterns, or comments.
  3. Some TypeScript declaration forms aren't covered (e.g., declare const, declare function).

These edge cases could lead to slightly inaccurate runtime line counts. For a heuristic complexity scorer used in automated discovery, this is likely acceptable, but consider documenting these limitations or adding a TODO for future AST-based analysis.

Consider adding a comment documenting these known limitations, or verify that the current accuracy is sufficient for the Ghost Stories candidate selection use case.


77-88: LGTM - Consider making configuration tunable in the future.

The complexity weights and baseline values are reasonable and well-documented with an example. The lower weight for imports (0.5) vs runtime lines (1.0) makes sense.

If future use cases require different complexity thresholds, consider making these values configurable via parameters rather than hard-coded constants.


95-111: Simplistic import counting may cause minor inaccuracies.

Line 100 counts imports by checking if a line starts with 'import'. This approach:

  • Counts commented-out imports: // import foo from 'bar'
  • Misses dynamic imports: const x = await import('foo')
  • May double-count type-only imports already excluded by countNonEmptyRuntimeLines

For a heuristic complexity analyzer in automated discovery, this is likely acceptable. However, consider refining the import detection if accuracy becomes important.

♻️ Potential improvement
-  const importCount = lines.filter((line) => line.trim().startsWith('import')).length;
+  const importCount = lines.filter((line) => {
+    const trimmed = line.trim();
+    return trimmed.startsWith('import ') && !trimmed.startsWith('//');
+  }).length;

This still won't be perfect but filters out obvious commented lines.

code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx (1)

177-180: Consider adding error handling for channel communication.

The executeGhostStoriesFlow function emits a channel event without error handling. While channel operations are typically fire-and-forget, consider whether any error handling or logging would be beneficial for debugging the Ghost Stories flow.

code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts (1)

114-123: Consider the convergence test performance.

The convergence test generates a string with ~1,100 lines using repeat(). While this effectively tests the normalization behavior, it could be slow if run frequently. Consider whether a smaller multiplier would still adequately test convergence.

code/core/src/core-server/utils/ghost-stories/test-annotations.ts (1)

4-16: Consider edge cases in empty render detection.

The isEmptyRender function may produce false positives for:

  • Lazy-loaded content that hasn't rendered yet
  • Content with CSS animations/transitions that start at zero size
  • Content with visibility: hidden temporarily during initialization

Consider whether these scenarios should be handled differently or if the current behavior is acceptable for Ghost Stories analysis.

code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts (1)

7-9: Remove unnecessary mock clearing.

vi.clearAllMocks() is called but no mocks are used in this test file. This can be removed.

♻️ Proposed fix
-  beforeEach(() => {
-    vi.clearAllMocks();
-  });
-
code/core/src/core-server/utils/ghost-stories/types.ts (1)

21-34: Consider consolidating redundant count fields in testSummary.

The testSummary object contains both passed/failed (lines 23-24) and passingCount/failingCount (lines 30-31), which appear to represent the same data. This redundancy could lead to inconsistencies if they diverge.

♻️ Suggested simplification
   testSummary: {
     total: number;
     passed: number;
     failed: number;
     failureRate: number;
     successRate: number;
     successRateWithoutEmptyRender: number;
     classifiedErrors: ClassifiedError[];
     uniqueErrorCount: number;
-    passingCount: number;
-    failingCount: number;
     passedButEmptyRenderCount: number;
     pending?: number;
   };
code/core/src/core-server/server-channel/ghost-stories-channel.test.ts (1)

100-100: Consider addressing test flakiness rather than retrying.

The { retry: 3 } option suggests these tests are flaky. While retries provide short-term reliability, they can mask timing issues or race conditions. Consider using more deterministic wait conditions or mock timers.

code/addons/vitest/src/vitest-plugin/index.ts (1)

114-115: Consider reusing the cached storybookComponentTestPaths on line 334.

storybookComponentTestPaths is computed once at line 115, but getComponentTestPaths() is called again at line 334. While the environment variable is unlikely to change mid-execution, reusing the cached value would be more consistent.

Note: This would require hoisting storybookComponentTestPaths to module scope or passing it through the plugin chain.

Also applies to: 334-334

code/core/src/core-server/utils/ghost-stories/get-candidates.ts (1)

86-86: Consider extracting the complexity threshold as a named constant.

The magic number 0.2 for the "simple" complexity threshold could be defined as a constant (e.g., SIMPLE_COMPLEXITY_THRESHOLD) for better maintainability and documentation.

code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts (1)

221-221: Pre-sort rules at module initialization for better performance.

DEFAULT_RULES.sort() is called on every categorizeError invocation. Since the rules are static, sorting once at module load would be more efficient.

♻️ Proposed fix
+// Pre-sort rules by priority (highest first)
+const SORTED_RULES = [...DEFAULT_RULES].sort((a, b) => b.priority - a.priority);
+
 export function categorizeError(
   message: string,
   stack?: string
 ): { category: ErrorCategory; matchedDependencies: string[] } {
-  const rules = DEFAULT_RULES.sort((a, b) => b.priority - a.priority);
   const ctx = buildErrorContext(message, stack);
-  const rule = rules.find((r) => r.match(ctx));
+  const rule = SORTED_RULES.find((r) => r.match(ctx));

   if (!rule) {
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da79150 and bd5a8be.

📒 Files selected for processing (20)
  • code/addons/a11y/src/preview.tsx
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-events/index.ts
  • code/core/src/core-server/presets/common-preset.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/test-annotations.ts
  • code/core/src/core-server/utils/ghost-stories/types.ts
  • code/core/src/csf/core-annotations.ts
  • code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx
  • code/core/src/manager/globals/exports.ts
  • code/core/src/telemetry/index.ts
  • code/core/src/telemetry/types.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{test,spec}.{ts,tsx}: Test files should follow the naming pattern *.test.ts, *.test.tsx, *.spec.ts, or *.spec.tsx
Follow the spy mocking rules defined in .cursor/rules/spy-mocking.mdc for consistent mocking patterns with Vitest

Files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/spy-mocking.mdc)

**/*.test.{ts,tsx,js,jsx}: Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Use vi.mocked() to type and access the mocked functions in Vitest tests
Implement mock behaviors in beforeEach blocks in Vitest tests
Mock all required dependencies that the test subject uses
Each mock implementation should return a Promise for async functions in Vitest
Mock implementations should match the expected return type of the original function
Mock all required properties and methods that the test subject uses in Vitest tests
Avoid direct function mocking without vi.mocked() in Vitest tests
Avoid mock implementations outside of beforeEach blocks in Vitest tests
Avoid mocking without the spy: true option in Vitest tests
Avoid inline mock implementations within test cases in Vitest tests
Avoid mocking only a subset of required dependencies in Vitest tests
Mock at the highest level of abstraction needed in Vitest tests
Keep mock implementations simple and focused in Vitest tests
Use type-safe mocking with vi.mocked() in Vitest tests
Document complex mock behaviors in Vitest tests
Group related mocks together in Vitest tests

Files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
**/*.{js,jsx,ts,tsx,json,md,html,css,scss}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Format code using Prettier with yarn prettier --write <file>

Files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.ts
  • code/core/src/telemetry/index.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/core/src/csf/core-annotations.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-events/index.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
  • code/core/src/core-server/utils/ghost-stories/types.ts
  • code/core/src/telemetry/types.ts
  • code/addons/a11y/src/preview.tsx
  • code/core/src/core-server/utils/ghost-stories/test-annotations.ts
  • code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx
  • code/core/src/core-server/presets/common-preset.ts
  • code/core/src/manager/globals/exports.ts
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run ESLint checks using yarn lint:js:cmd <file> or the full command cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives to fix linting errors before committing

Files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.ts
  • code/core/src/telemetry/index.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/core/src/csf/core-annotations.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-events/index.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
  • code/core/src/core-server/utils/ghost-stories/types.ts
  • code/core/src/telemetry/types.ts
  • code/addons/a11y/src/preview.tsx
  • code/core/src/core-server/utils/ghost-stories/test-annotations.ts
  • code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx
  • code/core/src/core-server/presets/common-preset.ts
  • code/core/src/manager/globals/exports.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Enable TypeScript strict mode across all packages

Files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.ts
  • code/core/src/telemetry/index.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/core/src/csf/core-annotations.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-events/index.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
  • code/core/src/core-server/utils/ghost-stories/types.ts
  • code/core/src/telemetry/types.ts
  • code/addons/a11y/src/preview.tsx
  • code/core/src/core-server/utils/ghost-stories/test-annotations.ts
  • code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx
  • code/core/src/core-server/presets/common-preset.ts
  • code/core/src/manager/globals/exports.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx,js,jsx}: Export functions from modules if they need to be tested
Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.ts
  • code/core/src/telemetry/index.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/core/src/csf/core-annotations.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-events/index.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
  • code/core/src/core-server/utils/ghost-stories/types.ts
  • code/core/src/telemetry/types.ts
  • code/addons/a11y/src/preview.tsx
  • code/core/src/core-server/utils/ghost-stories/test-annotations.ts
  • code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx
  • code/core/src/core-server/presets/common-preset.ts
  • code/core/src/manager/globals/exports.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{test,spec}.{ts,tsx,js,jsx}: Write meaningful unit tests that actually import and call the functions being tested, not just verify syntax patterns
Achieve high test coverage of business logic, aiming for 75%+ coverage of statements/lines
Cover all branches, conditions, edge cases, error paths, and different input variations in unit tests
Use vi.mock() to mock file system, loggers, and other external dependencies in tests

Files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use logger from storybook/internal/node-logger for server-side logging in Node.js code

Files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.ts
  • code/core/src/telemetry/index.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/core/src/csf/core-annotations.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-events/index.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
  • code/core/src/core-server/utils/ghost-stories/types.ts
  • code/core/src/telemetry/types.ts
  • code/addons/a11y/src/preview.tsx
  • code/core/src/core-server/utils/ghost-stories/test-annotations.ts
  • code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx
  • code/core/src/core-server/presets/common-preset.ts
  • code/core/src/manager/globals/exports.ts
🧠 Learnings (26)
📓 Common learnings
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking only a subset of required dependencies in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/core/src/csf/core-annotations.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Cover all branches, conditions, edge cases, error paths, and different input variations in unit tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Group related mocks together in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid inline mock implementations within test cases in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Write meaningful unit tests that actually import and call the functions being tested, not just verify syntax patterns

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Keep mock implementations simple and focused in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required properties and methods that the test subject uses in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Implement mock behaviors in `beforeEach` blocks in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mock implementations outside of `beforeEach` blocks in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Achieve high test coverage of business logic, aiming for 75%+ coverage of statements/lines

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock at the highest level of abstraction needed in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Each mock implementation should return a Promise for async functions in Vitest

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required dependencies that the test subject uses

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
  • code/core/src/csf/core-annotations.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Use `vi.mock()` to mock file system, loggers, and other external dependencies in tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts
📚 Learning: 2025-11-05T09:37:25.920Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/tooltip/WithTooltip.tsx:54-96
Timestamp: 2025-11-05T09:37:25.920Z
Learning: Repo: storybookjs/storybook — In code/core/src/components/components/tooltip/WithTooltip.tsx, the legacy WithTooltip implementation is intentionally reintroduced for backward compatibility and is deprecated; maintainers (per Sidnioulz) do not want maintenance or improvements on it. Prefer WithTooltipNew/Popover; avoid suggesting changes to WithTooltip.* going forward.

Applied to files:

  • code/core/src/csf/core-annotations.ts
  • code/core/src/core-server/utils/ghost-stories/test-annotations.ts
  • code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx
📚 Learning: 2025-09-24T09:39:39.233Z
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.

Applied to files:

  • code/core/src/csf/core-annotations.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/addons/a11y/src/preview.tsx
  • code/core/src/core-server/utils/ghost-stories/test-annotations.ts
  • code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx
  • code/core/src/manager/globals/exports.ts
📚 Learning: 2025-11-24T17:49:31.838Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T17:49:31.838Z
Learning: Applies to code/vitest.workspace.ts : Vitest configuration is centralized in `code/vitest.workspace.ts` for workspace setup

Applied to files:

  • code/addons/vitest/src/vitest-plugin/index.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid direct function mocking without `vi.mocked()` in Vitest tests

Applied to files:

  • code/addons/vitest/src/vitest-plugin/index.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking without the `spy: true` option in Vitest tests

Applied to files:

  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
📚 Learning: 2025-09-18T20:51:06.618Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/viewport/components/Tool.tsx:38-39
Timestamp: 2025-09-18T20:51:06.618Z
Learning: The useGlobals hook from storybook/manager-api returns a tuple where the third element (storyGlobals) is typed as Globals, not Globals | undefined. This means TypeScript guarantees it's always defined, making the `in` operator safe to use without additional null checks.

Applied to files:

  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/addons/a11y/src/preview.tsx
  • code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx
📚 Learning: 2025-09-18T20:51:06.618Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/viewport/components/Tool.tsx:38-39
Timestamp: 2025-09-18T20:51:06.618Z
Learning: In viewport tool code, when using the `useGlobals` hook from storybook/manager-api, the third returned value `storyGlobals` is guaranteed by TypeScript to be defined (not undefined/null), making the `in` operator safe to use without additional null checks.

Applied to files:

  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/addons/a11y/src/preview.tsx
📚 Learning: 2025-11-05T09:38:47.712Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx
📚 Learning: 2025-11-05T09:36:55.944Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Tabs/Tabs.stories.tsx:222-227
Timestamp: 2025-11-05T09:36:55.944Z
Learning: Repo: storybookjs/storybook PR: 32458 — In code/core/src/components/components/Button/Button.tsx (React/TypeScript), ButtonProps includes ariaLabel?: string | false and the component maps it to the DOM aria-label. Convention: ariaLabel is mandatory on all Button usages — provide a descriptive string for icon-only buttons; set ariaLabel=false when the button’s children already serve as the accessible name. Do not suggest using a raw aria-label prop on Button call sites.

Applied to files:

  • code/addons/a11y/src/preview.tsx
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx} : Use `logger` from `storybook/internal/node-logger` for server-side logging in Node.js code

Applied to files:

  • code/core/src/core-server/presets/common-preset.ts
🧬 Code graph analysis (7)
code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts (1)
code/core/src/core-server/utils/ghost-stories/component-analyzer.ts (1)
  • getComponentComplexity (95-111)
code/core/src/core-server/utils/ghost-stories/run-story-tests.ts (3)
code/core/src/core-server/utils/ghost-stories/types.ts (2)
  • GhostStoriesResponsePayload (17-37)
  • StoryTestResult (1-8)
code/core/src/common/utils/command.ts (1)
  • executeCommand (49-61)
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts (1)
  • extractUniqueCategorizedErrors (292-330)
code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts (2)
code/core/src/core-server/utils/ghost-stories/component-analyzer.ts (1)
  • getComponentComplexity (95-111)
code/core/src/core-server/utils/ghost-stories/get-candidates.ts (1)
  • getCandidatesForStorybook (64-106)
code/core/src/core-server/server-channel/ghost-stories-channel.test.ts (2)
code/core/src/core-server/server-channel/ghost-stories-channel.ts (1)
  • initGhostStoriesChannel (13-115)
code/core/src/telemetry/types.ts (1)
  • Options (103-110)
code/core/src/core-server/utils/ghost-stories/get-candidates.ts (2)
code/core/src/csf-tools/index.ts (1)
  • babelParse (5-5)
code/core/src/core-server/utils/ghost-stories/component-analyzer.ts (1)
  • getComponentComplexity (95-111)
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts (1)
code/core/src/core-server/utils/ghost-stories/types.ts (1)
  • StoryTestResult (1-8)
code/core/src/core-server/presets/common-preset.ts (1)
code/core/src/core-server/server-channel/ghost-stories-channel.ts (1)
  • initGhostStoriesChannel (13-115)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
  • GitHub Check: nx
🔇 Additional comments (22)
code/core/src/telemetry/types.ts (1)

42-43: LGTM!

The addition of 'ghost-stories' to the EventType union is straightforward and aligns with the new Ghost Stories telemetry events introduced in this PR.

code/core/src/core-server/presets/common-preset.ts (1)

35-35: LGTM - Ghost Stories channel integration follows established patterns.

The import and initialization of initGhostStoriesChannel follows the same pattern as other server channels (file search, create new story, open in editor, preview initialized). The integration is consistent with the existing architecture.

Also applies to: 264-264

code/core/src/csf/core-annotations.ts (1)

7-7: LGTM - Follows the established annotation pattern.

The ghost stories annotations are integrated consistently with other preview annotations, using the same CJS fallback pattern and positioned logically after test annotations.

Also applies to: 42-43

code/addons/a11y/src/preview.tsx (1)

20-26: LGTM - Correctly gates a11y tests during Ghost Stories discovery.

The addition of !isGhostStories to skip environment-independent a11y runs when Ghost Stories mode is active makes sense for the automated discovery flow. Verification confirms a11y is the unique addon with preview-level test hooks; no other addons require similar gating.

code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx (1)

49-49: Verify the one-time ghost stories flow semantics.

The hasRunGhostStoriesFlow ref never resets, meaning the ghost stories flow will only execute on the first modal open and never again, even if the modal is closed and reopened. If the intent is to run the flow on every modal open (or reset per user session), consider resetting the ref when the modal closes.

If the current one-time-ever behavior is intentional, consider adding a comment explaining why the flow should only run once across the entire modal lifecycle.

🔄 Proposed fix to reset on modal close

If the flow should run once per modal open:

  // Trigger the one-time flow when modal opens
  useEffect(() => {
    if (open && isRendererReact && !hasRunGhostStoriesFlow.current) {
      hasRunGhostStoriesFlow.current = true;
      executeGhostStoriesFlow();
    }
+   // Reset when modal closes to allow re-triggering on next open
+   if (!open) {
+     hasRunGhostStoriesFlow.current = false;
+   }
  }, [open, executeGhostStoriesFlow]);

Also applies to: 183-188

code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts (1)

1-124: Excellent test coverage!

The test suite comprehensively covers the getComponentComplexity function with boundary checks, multiple complexity scenarios, edge cases, and convergence behavior. The use of inline snapshots helps catch regressions.

code/core/src/core-server/utils/ghost-stories/test-annotations.ts (1)

25-25: Verify type safety of firstChild access.

Line 25 accesses canvasElement.firstChild which could be null or may not be an HTMLElement. The isEmptyRender function expects an HTMLElement for getComputedStyle to work correctly. Consider adding type guards or null checks.

🛡️ Suggested type-safe approach
-    const emptyRender = isEmptyRender(canvasElement.firstChild ?? canvasElement);
+    const targetElement = canvasElement.firstChild instanceof HTMLElement 
+      ? canvasElement.firstChild 
+      : canvasElement;
+    const emptyRender = isEmptyRender(targetElement);
code/core/src/manager/globals/exports.ts (1)

590-591: No action needed. The GHOST_STORIES_REQUEST and GHOST_STORIES_RESPONSE events are properly sourced through the generator. The generate-source-files.ts script bundles runtime.ts which imports from core-events/index.ts—where these events are defined—and automatically includes them in the generated exports.ts. These are not manual additions and will not be overwritten.

Likely an incorrect or invalid review comment.

code/core/src/core-events/index.ts (1)

91-93: LGTM! Clean event additions.

The new Ghost Stories events follow the established pattern for request/response pairs and are properly exported.

Also applies to: 165-166

code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts (1)

11-256: Excellent test coverage!

The test suite comprehensively covers all error categories, edge cases (empty results, mixed statuses, long messages), and aggregation logic. The tests are well-structured and clearly validate the error categorization functionality.

code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts (1)

18-155: Good test coverage with appropriate inline mocking.

The test suite thoroughly validates candidate selection logic across multiple scenarios. While mock implementations are inline rather than in beforeEach, this is appropriate here since each test requires different mock behaviors.

code/core/src/core-server/server-channel/ghost-stories-channel.ts (1)

13-115: Solid implementation of the Ghost Stories channel flow.

The channel initialization properly gates execution (telemetry, cache, metadata), generates candidates, runs tests, and reports telemetry. Error handling is comprehensive throughout.

code/core/src/core-server/utils/ghost-stories/run-story-tests.ts (1)

10-184: Well-structured test execution and result processing.

The function properly orchestrates Vitest execution, parses JSON output, transforms results into the expected format, categorizes errors, and computes comprehensive metrics. Error handling is thorough throughout.

code/core/src/core-server/utils/ghost-stories/types.ts (1)

1-8: LGTM!

The StoryTestResult interface is well-structured with clear status literals and optional error information.

code/core/src/core-server/server-channel/ghost-stories-channel.test.ts (2)

101-195: Good test coverage for the successful discovery flow.

The test validates the complete happy path: cache check, metadata retrieval, candidate generation, test execution, and telemetry reporting. The assertions on executeCommand and telemetry calls are thorough.


302-377: Comprehensive no-op condition coverage.

Tests appropriately verify early exit paths for telemetry disabled, already-ran state, non-React projects, and missing Vitest addon scenarios.

code/addons/vitest/src/vitest-plugin/index.ts (2)

104-112: LGTM - Environment-based component path discovery.

The simplified getComponentTestPaths() cleanly reads from STORYBOOK_COMPONENT_PATHS and handles the semicolon-delimited format. The filter(Boolean) correctly handles trailing separators or empty segments.


358-369: LGTM - Ghost Stories global integration.

The ghostStories.enabled global is correctly set based on the presence of STORYBOOK_COMPONENT_PATHS, enabling preview code to detect when running in Ghost Stories mode.

code/core/src/core-server/utils/ghost-stories/get-candidates.ts (1)

12-57: LGTM - Efficient AST-based candidate validation.

The isValidCandidate function correctly uses early termination via path.stop() when both conditions are met, optimizing traversal of large files.

code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts (3)

16-27: LGTM - Well-defined error category taxonomy.

The ERROR_CATEGORIES constant provides a comprehensive set of categories covering common React rendering issues (providers, hooks, modules, portals).


292-329: LGTM - Clean error aggregation implementation.

The extractUniqueCategorizedErrors function efficiently aggregates errors by category, deduplicates examples using Sets, and limits output size appropriately for telemetry purposes.


128-211: Well-structured rule-based categorization with clear priorities.

The rules are organized with sensible priority ordering (module errors > hooks > provider types > generic). The combination of message patterns and stack-based dependency detection provides robust categorization.

Comment on lines +28 to +34
// TODO: uncomment this later, it's commented out for debugging purposes
// const lastEvents = await getLastEvents();
// const lastPreviewFirstLoad = lastEvents['preview-first-load'];
// if (lastPreviewFirstLoad) {
// logger.debug('Skipping discovery run', { lastEvents });
// return;
// }
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove or resolve commented-out code before merging.

The commented-out code with "for debugging purposes" should be addressed before merging. Either enable the first-run check or remove the commented code if it's no longer needed.

This commented-out logic appears to be a safeguard to ensure ghost stories only runs on initial Storybook setup. If this check is still needed, uncomment and test it. If not, remove it entirely.

🤖 Prompt for AI Agents
In @code/core/src/core-server/server-channel/ghost-stories-channel.ts around
lines 28 - 34, Restore the first-run guard by uncommenting and wiring up the
check: call getLastEvents(), read lastEvents['preview-first-load'] into
lastPreviewFirstLoad, and if truthy log via logger.debug('Skipping discovery
run', { lastEvents }) and return from the handler (symbols: getLastEvents,
lastPreviewFirstLoad, logger.debug). Ensure you handle and surface errors from
getLastEvents (don’t swallow exceptions) and add/adjust a test or local run to
verify the discovery run is skipped on repeat loads; alternatively, if the
safeguard is no longer needed, remove the entire commented block to avoid dead
code.

Comment on lines +8 to +11
vi.mock('node:fs/promises');
vi.mock('glob');
vi.mock('storybook/internal/node-logger');
vi.mock('./component-analyzer');
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add spy: true option to mocks.

According to coding guidelines, all vi.mock() calls should include the spy: true option for consistent mocking patterns.

As per coding guidelines for **/*.test.{ts,tsx,js,jsx}.

♻️ Proposed fix
-vi.mock('node:fs/promises');
-vi.mock('glob');
-vi.mock('storybook/internal/node-logger');
-vi.mock('./component-analyzer');
+vi.mock('node:fs/promises', { spy: true });
+vi.mock('glob', { spy: true });
+vi.mock('storybook/internal/node-logger', { spy: true });
+vi.mock('./component-analyzer', { spy: true });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
vi.mock('node:fs/promises');
vi.mock('glob');
vi.mock('storybook/internal/node-logger');
vi.mock('./component-analyzer');
vi.mock('node:fs/promises', { spy: true });
vi.mock('glob', { spy: true });
vi.mock('storybook/internal/node-logger', { spy: true });
vi.mock('./component-analyzer', { spy: true });
🤖 Prompt for AI Agents
In @code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts around
lines 8 - 11, The test file uses vi.mock calls without the required spy option;
update each vi.mock invocation for 'node:fs/promises', 'glob',
'storybook/internal/node-logger', and './component-analyzer' to include the
option { spy: true } so the mocks follow the repository's testing guidelines;
ensure you pass the option as the second argument to vi.mock in
get-candidates.test.ts for all four mock declarations.

matchCount = files.length;

const candidates = await getCandidatesForStorybook(files, sampleSize);
logger.debug('candidates files:' + files.length);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Misleading debug log message.

The log message says "candidates files:" but logs files.length instead of candidates.length.

🐛 Proposed fix
-    logger.debug('candidates files:' + files.length);
+    logger.debug('candidates found: ' + candidates.length);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
logger.debug('candidates files:' + files.length);
logger.debug('candidates found: ' + candidates.length);
🤖 Prompt for AI Agents
In @code/core/src/core-server/utils/ghost-stories/get-candidates.ts at line 151,
The debug log incorrectly reports "candidates files:" but prints files.length;
update the logger.debug call (the invocation of logger.debug in
get-candidates.ts) to log candidates.length (and adjust the message text if
desired) so the message reflects the actual variable being measured (candidates)
instead of files.

Comment on lines 36 to 38
// TODO: DO NOT MERGE WITH THIS! IT'S FOR DEBUGGING PURPOSES ONLY!
console.log('telemetry ', { eventType, payload, options });
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Remove debug code before merging.

This debug code disables all telemetry functionality and uses console.log directly, which violates the coding guidelines. The TODO comment confirms this should not be merged.

🔧 Proposed fix

Remove the debug code to restore telemetry:

-  // TODO: DO NOT MERGE WITH THIS! IT'S FOR DEBUGGING PURPOSES ONLY!
-  console.log('telemetry ', { eventType, payload, options });
-  return;
   // Don't notify on boot since it can lead to double notification in `sb init`.

As per coding guidelines, for files matching **/*.{ts,tsx,js,jsx}: "Do not use console.log, console.warn, or console.error directly" and for code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx}: "Use logger from storybook/internal/node-logger for server-side logging."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// TODO: DO NOT MERGE WITH THIS! IT'S FOR DEBUGGING PURPOSES ONLY!
console.log('telemetry ', { eventType, payload, options });
return;
🤖 Prompt for AI Agents
In @code/core/src/telemetry/index.ts around lines 36 - 38, Remove the temporary
debug early-return that logs telemetry and short-circuits functionality: delete
the console.log('telemetry ', { eventType, payload, options }) and the following
return so the telemetry function resumes its normal flow; if any server-side
logging is needed, replace direct console calls with the shared logger
(storybook/internal/node-logger) and log contextual error/info messages instead
rather than using console.log.

@storybook-app-bot
Copy link

storybook-app-bot bot commented Jan 8, 2026

Package Benchmarks

Commit: fabaa0d, ran on 8 January 2026 at 23:52:18 UTC

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

@storybook/builder-webpack5

Before After Difference
Dependency count 192 192 0
Self size 75 KB 75 KB 0 B
Dependency size 32.21 MB 32.23 MB 🚨 +22 KB 🚨
Bundle Size Analyzer Link Link

storybook

Before After Difference
Dependency count 49 49 0
Self size 20.20 MB 20.23 MB 🚨 +28 KB 🚨
Dependency size 16.52 MB 16.52 MB 0 B
Bundle Size Analyzer Link Link

@storybook/angular

Before After Difference
Dependency count 192 192 0
Self size 118 KB 118 KB 0 B
Dependency size 30.40 MB 30.42 MB 🚨 +22 KB 🚨
Bundle Size Analyzer Link Link

@storybook/ember

Before After Difference
Dependency count 196 196 0
Self size 15 KB 15 KB 🚨 +18 B 🚨
Dependency size 28.93 MB 28.95 MB 🚨 +22 KB 🚨
Bundle Size Analyzer Link Link

@storybook/nextjs

Before After Difference
Dependency count 538 538 0
Self size 646 KB 646 KB 0 B
Dependency size 59.17 MB 59.20 MB 🚨 +22 KB 🚨
Bundle Size Analyzer Link Link

@storybook/nextjs-vite

Before After Difference
Dependency count 127 127 0
Self size 1.12 MB 1.12 MB 🎉 -36 B 🎉
Dependency size 21.79 MB 21.81 MB 🚨 +22 KB 🚨
Bundle Size Analyzer Link Link

@storybook/react-native-web-vite

Before After Difference
Dependency count 159 159 0
Self size 30 KB 30 KB 0 B
Dependency size 22.97 MB 22.99 MB 🚨 +22 KB 🚨
Bundle Size Analyzer Link Link

@storybook/react-vite

Before After Difference
Dependency count 117 117 0
Self size 35 KB 35 KB 0 B
Dependency size 19.58 MB 19.61 MB 🚨 +22 KB 🚨
Bundle Size Analyzer Link Link

@storybook/react-webpack5

Before After Difference
Dependency count 278 278 0
Self size 24 KB 24 KB 0 B
Dependency size 44.10 MB 44.12 MB 🚨 +22 KB 🚨
Bundle Size Analyzer Link Link

@storybook/server-webpack5

Before After Difference
Dependency count 204 204 0
Self size 16 KB 16 KB 0 B
Dependency size 33.47 MB 33.49 MB 🚨 +22 KB 🚨
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 183 183 0
Self size 775 KB 775 KB 0 B
Dependency size 67.26 MB 67.31 MB 🚨 +50 KB 🚨
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 176 176 0
Self size 30 KB 30 KB 0 B
Dependency size 65.83 MB 65.88 MB 🚨 +50 KB 🚨
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 50 50 0
Self size 999 KB 999 KB 0 B
Dependency size 36.72 MB 36.75 MB 🚨 +28 KB 🚨
Bundle Size Analyzer node node

@storybook/preset-react-webpack

Before After Difference
Dependency count 170 170 0
Self size 18 KB 18 KB 🚨 +24 B 🚨
Dependency size 31.24 MB 31.26 MB 🚨 +22 KB 🚨
Bundle Size Analyzer Link Link

@storybook/react

Before After Difference
Dependency count 57 57 0
Self size 723 KB 723 KB 0 B
Dependency size 12.92 MB 12.94 MB 🚨 +22 KB 🚨
Bundle Size Analyzer Link Link

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.

Review Summary

I've reviewed the PR and the CodeRabbit comments. Here are my observations:

CodeRabbit Comments Assessment

1. Mock path mismatch (Critical) ✅ Valid

vi.mock('../utils/ghost-stories/story-generation', ...) // Wrong path

Should be:

vi.mock('../utils/ghost-stories/get-candidates', ...)

This is indeed critical - the mock won't work correctly as it targets a non-existent module.

2. Duplicate error entry ✅ Valid
Lines 287-291 have 'Expected button to be disabled' appearing twice. This appears to be a copy-paste error.

3. Commented-out code ⚠️ Acceptable for now
The TODO comment about getLastEvents() is fine for an experimental feature, but should be tracked for cleanup.

Additional Issues Found

5. Test expectations don't match implementation (Critical)
The tests expect uniqueErrors in the telemetry payload:

testResults: {
  uniqueErrors: [],
  ...
}

But run-story-tests.ts returns classifiedErrors:

testSummary: {
  classifiedErrors,
  ...
}

This mismatch will cause test failures.

6. stdio mismatch between test and implementation
Test expects:

stdio: 'ignore'

But run-story-tests.ts has:

stdio: 'pipe'

7. Import paths in run-story-tests.ts
Should use Node.js protocol prefix for consistency:

// Current
import { existsSync } from 'fs';
import { mkdir, readFile } from 'fs/promises';

// Recommended
import { existsSync } from 'node:fs';
import { mkdir, readFile } from 'node:fs/promises';

Code Quality Observations

The overall architecture is solid:

  • Good separation of concerns (candidates discovery, test running, error categorization)
  • Comprehensive error categorization with priority-based matching
  • Proper telemetry integration
  • The caching mechanism to prevent repeated runs is well designed

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.

Approving as pair-reviewed.

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: 5

🤖 Fix all issues with AI agents
In @code/core/src/core-server/server-channel/ghost-stories-channel.ts:
- Around line 13-21: The function initGhostStoriesChannel returns undefined when
coreOptions.disableTelemetry is true but returns the channel later, causing
inconsistency; change the early exit to return the provided channel instead of
nothing. Specifically, in the branch guarded by coreOptions.disableTelemetry
(where logger.debug('Skipping discovery run - telemetry disabled') is called),
update the return to return channel so callers of initGhostStoriesChannel always
receive the Channel object.

In @code/core/src/core-server/utils/ghost-stories/get-candidates.ts:
- Around line 156-165: The empty-files check currently happens after calling
getCandidatesForStorybook; move the files.length === 0 check to occur
immediately after obtaining files (before invoking getCandidatesForStorybook) so
we return early with { candidates: [], matchCount } and avoid calling
getCandidatesForStorybook with an empty files array; reference the
variables/functions files, getCandidatesForStorybook(files, sampleSize),
sampleSize, logger.warn and globPattern when making the change.

In @code/core/src/core-server/utils/ghost-stories/run-story-tests.ts:
- Line 5: The import uses join from 'path/posix' which forces POSIX separators
and can break on Windows; change the import to use the platform-aware module
(import { join } from 'path') or otherwise use path.join so path joins use the
OS-specific separators; update any usage of join in run-story-tests.ts
accordingly to avoid hardcoded POSIX behavior.
- Around line 54-61: The early return when the output file is missing is
discarding the previously computed duration by hardcoding duration: 0; update
the return in the existsSync(outputFile) false branch to use the calculated
duration variable (e.g., duration) instead of 0 so the failure report reflects
the actual elapsed time; locate the failing return in
runStoryTests/run-story-tests (the block checking existsSync(outputFile) and
returning success:false) and replace duration: 0 with the previously computed
duration variable.
- Around line 140-141: The catch block in run-story-tests.ts currently calls
console.error('Error running story tests:', error); replace this with the
project logger: import { logger } from 'storybook/internal/node-logger' (if not
already imported) and call logger.error with the same context and error details
(e.g., logger.error('Error running story tests:', error) or include error.stack)
inside the catch in the runStoryTests (or similarly named) function so
server-side logging uses the standardized logger.
🧹 Nitpick comments (5)
code/core/src/core-server/server-channel/ghost-stories-channel.ts (1)

54-55: Consider using await error handling for cache.set.

If cache.set fails, the error would be unhandled. Consider wrapping in try-catch or using .catch() to prevent potential unhandled promise rejections, especially since subsequent operations depend on this state.

code/core/src/core-server/utils/ghost-stories/component-analyzer.ts (1)

19-27: Import lines are counted twice, inflating their contribution.

Import statements are included in nonEmptyLines (weight 1.0) and also counted separately in importCount (weight 0.5), resulting in an effective weight of 1.5× per import line. The comment on line 5 says "Imports can be cheap, so they get a lower weight," but they actually receive a higher weight than regular lines.

If the intent is for imports to contribute less than regular code lines, consider subtracting importCount from nonEmptyLines:

Suggested fix
  const rawComplexity =
-   nonEmptyLines * COMPLEXITY_CONFIG.locWeight + importCount * COMPLEXITY_CONFIG.importWeight;
+   (nonEmptyLines - importCount) * COMPLEXITY_CONFIG.locWeight + importCount * COMPLEXITY_CONFIG.importWeight;
code/core/src/core-server/utils/ghost-stories/run-story-tests.ts (1)

70-71: Add null checks for Vitest result structure.

If testResults.testResults is undefined or not an array (e.g., due to a Vitest version change or malformed output), iterating over it will throw. Consider adding defensive checks.

Suggested fix
-    for (const testSuite of testResults.testResults) {
+    for (const testSuite of testResults.testResults ?? []) {
       for (const assertion of testSuite.assertionResults) {
code/core/src/core-server/utils/ghost-stories/types.ts (1)

10-15: Consider using ErrorCategory enum and adding matchedDependencies.

Based on the snippet from categorize-render-errors.ts (lines 314-318), the actual categorized errors include matchedDependencies: string[]. This field is missing from ClassifiedError, which may cause data loss when serializing. Also, category could use a stricter type if an ErrorCategory enum exists.

Suggested type alignment
 export interface ClassifiedError {
   category: string;
   description: string;
   count: number;
   examples: string[];
+  matchedDependencies: string[];
 }
code/core/src/core-server/utils/ghost-stories/get-candidates.ts (1)

79-81: Consider logging parse failures for debugging.

Silent failures in the catch block make it difficult to diagnose why certain files are skipped. A debug-level log would help troubleshoot candidate discovery issues.

Suggested improvement
     } catch {
+      logger.debug(`Skipping file due to read/parse error: ${file}`);
       continue;
     }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bd5a8be and aca427a.

📒 Files selected for processing (6)
  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,ts,tsx,json,md,html,css,scss}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Format code using Prettier with yarn prettier --write <file>

Files:

  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/types.ts
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run ESLint checks using yarn lint:js:cmd <file> or the full command cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives to fix linting errors before committing

Files:

  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/types.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Enable TypeScript strict mode across all packages

Files:

  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/types.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx,js,jsx}: Export functions from modules if they need to be tested
Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/types.ts
code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use logger from storybook/internal/node-logger for server-side logging in Node.js code

Files:

  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-server/utils/ghost-stories/component-analyzer.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/types.ts
🧠 Learnings (15)
📚 Learning: 2025-11-05T09:38:47.712Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.

Applied to files:

  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
📚 Learning: 2025-09-24T09:39:39.233Z
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.

Applied to files:

  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Write meaningful unit tests that actually import and call the functions being tested, not just verify syntax patterns

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid inline mock implementations within test cases in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Group related mocks together in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking only a subset of required dependencies in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Keep mock implementations simple and focused in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Implement mock behaviors in `beforeEach` blocks in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required properties and methods that the test subject uses in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Each mock implementation should return a Promise for async functions in Vitest

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mock implementations outside of `beforeEach` blocks in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx} : Use `logger` from `storybook/internal/node-logger` for server-side logging in Node.js code

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to code/{renderers}/**/*.{ts,tsx,js,jsx} : Use `logger` from `storybook/internal/client-logger` for client-side logging in browser code

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Do not use `console.log`, `console.warn`, or `console.error` directly unless in isolated files where importing loggers would significantly increase bundle size

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
🧬 Code graph analysis (3)
code/core/src/core-server/server-channel/ghost-stories-channel.ts (4)
code/core/src/telemetry/types.ts (1)
  • Options (103-110)
code/core/src/core-server/utils/ghost-stories/get-candidates.ts (1)
  • getComponentCandidates (114-181)
code/core/src/telemetry/index.ts (1)
  • telemetry (31-75)
code/core/src/core-server/utils/ghost-stories/run-story-tests.ts (1)
  • runStoryTests (10-149)
code/core/src/core-server/utils/ghost-stories/run-story-tests.ts (3)
code/core/src/core-server/utils/ghost-stories/types.ts (2)
  • GhostStoriesResponsePayload (17-33)
  • StoryTestResult (1-8)
code/core/src/common/utils/command.ts (1)
  • executeCommand (49-61)
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts (1)
  • extractUniqueCategorizedErrors (292-330)
code/core/src/core-server/utils/ghost-stories/get-candidates.ts (2)
code/core/src/csf-tools/index.ts (1)
  • babelParse (5-5)
code/core/src/core-server/utils/ghost-stories/component-analyzer.ts (1)
  • getComponentComplexity (19-34)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
  • GitHub Check: nx
🔇 Additional comments (8)
code/core/src/core-server/server-channel/ghost-stories-channel.ts (3)

86-98: Good structured telemetry payload with conditional error field.

The telemetry call correctly spreads the error conditionally and includes comprehensive metrics (matchCount, generatedCount, durations, testSummary). The implementation properly handles both success and partial failure states.


108-111: Good use of finally block for response emission.

Emitting GHOST_STORIES_RESPONSE in the finally block ensures the response is always sent regardless of success, failure, or early returns within the try block. This is a robust pattern for event-driven flows.


42-52: The in operator check is correct and appropriate for the metadata.addons structure.

The metadata.addons field is typed as Record<string, StorybookAddon> (an object with addon names as keys), not an array. The check '@storybook/addon-vitest' in metadata.addons correctly uses the in operator to verify key existence in this object structure.

Likely an incorrect or invalid review comment.

code/core/src/core-server/utils/ghost-stories/component-analyzer.ts (1)

29-33: Normalization and clamping logic is correct.

The formula normalizes against the configured baseline and clamps to a maximum of 1, ensuring a consistent 0–1 output range.

code/core/src/core-server/utils/ghost-stories/run-story-tests.ts (1)

108-131: Test summary computation is well-structured.

The metrics calculation (success rates, empty render handling, error classification) provides comprehensive telemetry data. The successRateWithoutEmptyRender metric is a useful addition for distinguishing meaningful passes.

code/core/src/core-server/utils/ghost-stories/types.ts (1)

17-33: Well-structured payload interface.

The GhostStoriesResponsePayload provides a clear contract for the test results, with optional testSummary for successful runs and optional error for failures. The inline type for testSummary is comprehensive.

code/core/src/core-server/utils/ghost-stories/get-candidates.ts (2)

12-57: Efficient AST traversal with early exit.

The isValidCandidate function correctly uses path.stop() to exit traversal early once both conditions (JSX and export) are detected. This is an efficient pattern for large files.


93-102: Good early termination and sorting logic.

The function efficiently returns early when enough simple candidates are found and sorts by complexity to prioritize simpler components. This aligns well with the goal of finding easy-to-test candidates.

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: 3

🤖 Fix all issues with AI agents
In
@code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts:
- Line 11: The test describe block is misnamed: it uses
"extractUniqueCategorizedErrors" while the tests exercise
extractCategorizedErrors; rename the describe string to
"extractCategorizedErrors" so test output matches the actual function under test
(update the describe declaration in categorize-render-errors.test.ts that wraps
the extractCategorizedErrors tests).

In @code/core/src/core-server/utils/ghost-stories/run-story-tests.ts:
- Line 140: Replace the direct console.error call with the structured server
logger: add an import for the logger from 'storybook/internal/node-logger'
(e.g., import { logger } from 'storybook/internal/node-logger') at the top of
the file, then replace the console.error('Error running story tests:', error)
invocation with a logger.error usage that logs the same message and the error
object (e.g., logger.error(...) so the server-side structured logger is used
instead of console.error).

In @code/core/src/telemetry/ecosystem-identifier.ts:
- Around line 76-93: The UI_LIBRARY_PACKAGES list includes the entry 'radix-ui'
which won't match scoped Radix UI packages; update the array
(UI_LIBRARY_PACKAGES) to use the scoped pattern '@radix-ui/*' so packages like
'@radix-ui/react-dialog' are correctly matched.
🧹 Nitpick comments (3)
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts (1)

7-9: Remove unnecessary vi.clearAllMocks() call.

The beforeEach hook clears mocks, but this test file doesn't use any mocks. Since there are no mocks to clear, this call is unnecessary and can be removed.

♻️ Proposed refactor
-  beforeEach(() => {
-    vi.clearAllMocks();
-  });
code/core/src/telemetry/get-known-packages.test.ts (1)

169-195: Consider moving mock override to a nested describe block with its own beforeEach.

The inline mock implementation (lines 170-173) deviates from the coding guideline to implement mock behaviors in beforeEach blocks. For test-specific mock overrides, a nested describe with its own beforeEach improves consistency.

♻️ Suggested refactor
-    it('should handle special version specifiers', async () => {
-      vi.mocked(getActualPackageVersion).mockImplementation(async (pkg: string) => ({
-        name: pkg,
-        version: 'file:../some/path',
-      }));
-
-      const packageJson: PackageJson = {
+    describe('with special version specifiers', () => {
+      beforeEach(() => {
+        vi.mocked(getActualPackageVersion).mockImplementation(async (pkg: string) => ({
+          name: pkg,
+          version: 'file:../some/path',
+        }));
+      });
+
+      it('should handle special version specifiers', async () => {
+        const packageJson: PackageJson = {
code/core/src/telemetry/get-known-packages.ts (1)

114-124: Consider shorthand property syntax.

The return object uses verbose syntax ({ testPackages: testPackages }). Shorthand property syntax is more idiomatic.

♻️ Suggested simplification
   return {
-    ...(testPackages && { testPackages: testPackages }),
-    ...(stylingPackages && { stylingPackages: stylingPackages }),
-    ...(stateManagementPackages && {
-      stateManagementPackages: stateManagementPackages,
-    }),
-    ...(dataFetchingPackages && { dataFetchingPackages: dataFetchingPackages }),
-    ...(uiLibraryPackages && { uiLibraryPackages: uiLibraryPackages }),
-    ...(i18nPackages && { i18nPackages: i18nPackages }),
-    ...(routerPackages && { routerPackages: routerPackages }),
+    ...(testPackages && { testPackages }),
+    ...(stylingPackages && { stylingPackages }),
+    ...(stateManagementPackages && { stateManagementPackages }),
+    ...(dataFetchingPackages && { dataFetchingPackages }),
+    ...(uiLibraryPackages && { uiLibraryPackages }),
+    ...(i18nPackages && { i18nPackages }),
+    ...(routerPackages && { routerPackages }),
   };
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aca427a and 0cda5ae.

📒 Files selected for processing (9)
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/telemetry/get-known-packages.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/telemetry/storybook-metadata.ts
  • code/core/src/telemetry/types.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{test,spec}.{ts,tsx}: Test files should follow the naming pattern *.test.ts, *.test.tsx, *.spec.ts, or *.spec.tsx
Follow the spy mocking rules defined in .cursor/rules/spy-mocking.mdc for consistent mocking patterns with Vitest

Files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/spy-mocking.mdc)

**/*.test.{ts,tsx,js,jsx}: Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Use vi.mocked() to type and access the mocked functions in Vitest tests
Implement mock behaviors in beforeEach blocks in Vitest tests
Mock all required dependencies that the test subject uses
Each mock implementation should return a Promise for async functions in Vitest
Mock implementations should match the expected return type of the original function
Mock all required properties and methods that the test subject uses in Vitest tests
Avoid direct function mocking without vi.mocked() in Vitest tests
Avoid mock implementations outside of beforeEach blocks in Vitest tests
Avoid mocking without the spy: true option in Vitest tests
Avoid inline mock implementations within test cases in Vitest tests
Avoid mocking only a subset of required dependencies in Vitest tests
Mock at the highest level of abstraction needed in Vitest tests
Keep mock implementations simple and focused in Vitest tests
Use type-safe mocking with vi.mocked() in Vitest tests
Document complex mock behaviors in Vitest tests
Group related mocks together in Vitest tests

Files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
**/*.{js,jsx,ts,tsx,json,md,html,css,scss}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Format code using Prettier with yarn prettier --write <file>

Files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/get-known-packages.ts
  • code/core/src/telemetry/storybook-metadata.ts
  • code/core/src/telemetry/types.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run ESLint checks using yarn lint:js:cmd <file> or the full command cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives to fix linting errors before committing

Files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/get-known-packages.ts
  • code/core/src/telemetry/storybook-metadata.ts
  • code/core/src/telemetry/types.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Enable TypeScript strict mode across all packages

Files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/get-known-packages.ts
  • code/core/src/telemetry/storybook-metadata.ts
  • code/core/src/telemetry/types.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx,js,jsx}: Export functions from modules if they need to be tested
Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/get-known-packages.ts
  • code/core/src/telemetry/storybook-metadata.ts
  • code/core/src/telemetry/types.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{test,spec}.{ts,tsx,js,jsx}: Write meaningful unit tests that actually import and call the functions being tested, not just verify syntax patterns
Achieve high test coverage of business logic, aiming for 75%+ coverage of statements/lines
Cover all branches, conditions, edge cases, error paths, and different input variations in unit tests
Use vi.mock() to mock file system, loggers, and other external dependencies in tests

Files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use logger from storybook/internal/node-logger for server-side logging in Node.js code

Files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/get-known-packages.ts
  • code/core/src/telemetry/storybook-metadata.ts
  • code/core/src/telemetry/types.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
🧠 Learnings (28)
📓 Common learnings
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking only a subset of required dependencies in Vitest tests

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Write meaningful unit tests that actually import and call the functions being tested, not just verify syntax patterns

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Cover all branches, conditions, edge cases, error paths, and different input variations in unit tests

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors in Vitest tests

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required dependencies that the test subject uses

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Group related mocks together in Vitest tests

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required properties and methods that the test subject uses in Vitest tests

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Achieve high test coverage of business logic, aiming for 75%+ coverage of statements/lines

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `vi.mock()` with the `spy: true` option for all package and file mocks in Vitest tests

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Keep mock implementations simple and focused in Vitest tests

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Implement mock behaviors in `beforeEach` blocks in Vitest tests

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mock implementations outside of `beforeEach` blocks in Vitest tests

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Each mock implementation should return a Promise for async functions in Vitest

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock at the highest level of abstraction needed in Vitest tests

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid direct function mocking without `vi.mocked()` in Vitest tests

Applied to files:

  • code/core/src/telemetry/get-known-packages.test.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid inline mock implementations within test cases in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-09-17T07:31:04.432Z
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32484
File: code/core/package.json:326-326
Timestamp: 2025-09-17T07:31:04.432Z
Learning: In Storybook's core package, dependencies like `open` are bundled into the final distribution during the build process, so they should remain in devDependencies rather than being moved to dependencies. End users don't need these packages as separate runtime dependencies since they're included in the bundled code.

Applied to files:

  • code/core/src/telemetry/storybook-metadata.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Export functions from modules if they need to be tested

Applied to files:

  • code/core/src/telemetry/ecosystem-identifier.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Use `vi.mock()` to mock file system, loggers, and other external dependencies in tests

Applied to files:

  • code/core/src/telemetry/storybook-metadata.test.ts
📚 Learning: 2025-11-24T17:49:31.838Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T17:49:31.838Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : Follow the spy mocking rules defined in `.cursor/rules/spy-mocking.mdc` for consistent mocking patterns with Vitest

Applied to files:

  • code/core/src/telemetry/storybook-metadata.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `vi.mocked()` to type and access the mocked functions in Vitest tests

Applied to files:

  • code/core/src/telemetry/storybook-metadata.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use type-safe mocking with `vi.mocked()` in Vitest tests

Applied to files:

  • code/core/src/telemetry/storybook-metadata.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking without the `spy: true` option in Vitest tests

Applied to files:

  • code/core/src/telemetry/storybook-metadata.test.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx} : Use `logger` from `storybook/internal/node-logger` for server-side logging in Node.js code

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to code/{renderers}/**/*.{ts,tsx,js,jsx} : Use `logger` from `storybook/internal/client-logger` for client-side logging in browser code

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Do not use `console.log`, `console.warn`, or `console.error` directly unless in isolated files where importing loggers would significantly increase bundle size

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-05T09:38:47.712Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
🧬 Code graph analysis (6)
code/core/src/telemetry/get-known-packages.test.ts (2)
code/core/src/telemetry/get-known-packages.ts (2)
  • getSafeVersionSpecifier (29-66)
  • analyzeEcosystemPackages (68-125)
code/core/src/types/modules/core-common.ts (1)
  • PackageJson (159-159)
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts (2)
code/core/src/core-server/utils/ghost-stories/types.ts (1)
  • StoryTestResult (1-8)
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts (1)
  • extractCategorizedErrors (254-299)
code/core/src/telemetry/get-known-packages.ts (1)
code/core/src/telemetry/ecosystem-identifier.ts (8)
  • matchesPackagePattern (108-113)
  • TEST_PACKAGES (3-24)
  • STYLING_PACKAGES (26-44)
  • STATE_MANAGEMENT_PACKAGES (46-59)
  • DATA_FETCHING_PACKAGES (61-74)
  • UI_LIBRARY_PACKAGES (76-93)
  • I18N_PACKAGES (95-95)
  • ROUTER_PACKAGES (97-106)
code/core/src/telemetry/storybook-metadata.ts (1)
code/core/src/telemetry/get-known-packages.ts (1)
  • analyzeEcosystemPackages (68-125)
code/core/src/telemetry/types.ts (1)
code/core/src/telemetry/get-known-packages.ts (1)
  • KnownPackagesList (19-27)
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts (2)
code/core/src/telemetry/ecosystem-identifier.ts (4)
  • isStateManagementPackage (115-117)
  • isRouterPackage (123-125)
  • isStylingPackage (119-121)
  • isI18nPackage (127-129)
code/core/src/core-server/utils/ghost-stories/types.ts (1)
  • StoryTestResult (1-8)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
  • GitHub Check: nx
🔇 Additional comments (16)
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts (1)

12-256: Excellent test coverage!

The test suite comprehensively covers:

  • Empty and passing test scenarios
  • All error categories (unknown, theme, state, router, hooks, modules, render)
  • Error aggregation and sorting by count
  • Message truncation
  • Edge cases with filtering and empty input

The tests are meaningful, well-structured, and follow best practices for unit testing.

code/core/src/core-server/utils/ghost-stories/run-story-tests.ts (1)

10-148: Robust implementation with comprehensive error handling.

The function correctly:

  • Creates necessary cache directories
  • Executes Vitest with proper arguments and environment variables
  • Handles command failures gracefully
  • Transforms Vitest results to the expected format
  • Computes detailed metrics including empty render detection
  • Extracts and categorizes errors
  • Returns structured payload on both success and failure
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts (3)

55-75: Well-designed context building with dependency extraction.

The buildErrorContext function correctly:

  • Normalizes message and stack for case-insensitive matching
  • Extracts dependency names from stack traces using the /deps/{name}.js pattern
  • Provides a clean context object for rule matching

90-173: Comprehensive rule-based categorization with proper priority ordering.

The prioritized rule system effectively handles:

  • High-priority specific errors (module imports, hooks)
  • Provider-specific errors with dependency matching
  • Fallback to generic categories

The combination of message matching and stack dependency analysis (using ecosystem identifier functions) provides robust categorization.


254-299: Solid aggregation logic with proper uniqueness tracking.

The extractCategorizedErrors function correctly:

  • Filters failed tests with error messages
  • Counts unique errors by full message (line 281)
  • Aggregates by category with examples and matched dependencies
  • Sorts results by count descending
  • Limits examples to 3 per category and truncates to 100 chars
code/core/src/telemetry/types.ts (1)

5-5: LGTM!

The type changes are well-structured:

  • KnownPackagesList import aligns with the new ecosystem package analysis
  • ghost-stories event type follows the existing union pattern
  • Optional knownPackages field appropriately replaces testPackages with richer categorization

Also applies to: 43-44, 81-81

code/core/src/telemetry/get-known-packages.test.ts (2)

54-123: Clarify expected behavior: emotion package not matching @emotion/* pattern.

Line 60 includes emotion: '11.0.0' in the test dependencies, but the expected stylingPackages (lines 87-90) excludes it. This is correct since STYLING_PACKAGES contains @emotion/* (scoped pattern) but not the unscoped emotion package.

Consider adding a brief inline comment to document this intentional exclusion, as the discrepancy may confuse future maintainers.


1-209: Good test coverage following mocking guidelines.

The test file properly uses vi.mock with spy: true and implements mock behaviors in beforeEach. Coverage includes version specifier normalization, multiple package groups, scoped packages, and edge cases.

code/core/src/telemetry/storybook-metadata.test.ts (2)

504-548: LGTM!

The test correctly validates the knownPackages integration path. The mock data structure aligns with KnownPackagesList and the assertion confirms proper propagation through computeStorybookMetadata.


33-37: Mocking pattern follows guidelines.

The new mocks for get-framework-info, get-package-manager-info, get-portable-stories-usage, get-application-file-count, and get-known-packages correctly use vi.mock with spy: true, and implementations are placed in beforeEach as required.

Also applies to: 80-99

code/core/src/telemetry/storybook-metadata.ts (1)

25-25: LGTM!

The integration is clean and follows existing patterns. The analyzeEcosystemPackages call is correctly awaited and placed alongside related metadata population logic.

Also applies to: 95-96

code/core/src/telemetry/get-known-packages.ts (2)

29-66: Well-implemented version specifier normalization.

The function handles edge cases comprehensively: falsy values, wildcards, custom protocols, dist-tags, and semver coercion. The use of semver.coerce appropriately normalizes complex version strings.


93-112: Intentional asymmetry in version resolution?

testPackages resolves actual installed versions via getActualPackageVersion (lines 93-105), while other categories (lines 107-112) use declared versions from package.json. This may be intentional (test packages are more critical for Ghost Stories), but consider documenting this design decision or unifying the approach if consistency is preferred.

code/core/src/telemetry/ecosystem-identifier.ts (3)

108-113: LGTM!

The matchesPackagePattern utility correctly leverages picomatch.isMatch for glob-based pattern matching. The function is concise and delegates pattern matching efficiently.


1-129: Good module structure with clear categorization.

The ecosystem identifier provides well-organized package patterns with appropriate use of as const for type safety. The helper predicates follow a consistent delegation pattern.


84-84: > Likely an incorrect or invalid review comment.


return enhancedResponse;
} catch (error) {
console.error('Error running story tests:', error);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Replace console.error with logger from storybook/internal/node-logger.

Direct use of console.error violates the coding guidelines for server-side code. Use the logger from storybook/internal/node-logger instead.

As per coding guidelines, server-side Node.js code should use the structured logger.

🐛 Proposed fix

Add the import at the top of the file:

 import { executeCommand, resolvePathInStorybookCache } from 'storybook/internal/common';
+import { logger } from 'storybook/internal/node-logger';

Then replace the console.error call:

-    console.error('Error running story tests:', error);
+    logger.error('Error running story tests:', error);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @code/core/src/core-server/utils/ghost-stories/run-story-tests.ts at line
140, Replace the direct console.error call with the structured server logger:
add an import for the logger from 'storybook/internal/node-logger' (e.g., import
{ logger } from 'storybook/internal/node-logger') at the top of the file, then
replace the console.error('Error running story tests:', error) invocation with a
logger.error usage that logs the same message and the error object (e.g.,
logger.error(...) so the server-side structured logger is used instead of
console.error).

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: 6

🤖 Fix all issues with AI agents
In @code/core/src/core-server/utils/ghost-stories/get-candidates.ts:
- Around line 71-81: The catch block in the loop that reads candidate files is
silently swallowing errors; update the catch to log the error at debug level
including the file path (variable "file") and the caught error so failures in
readFile or isValidCandidate are visible; specifically, inside the catch after
the readFile/isValidCandidate try, call a debug logger (e.g., console.debug or
the module's logger) with a clear message referencing "file" and the caught
error before continuing.

In @code/core/src/core-server/utils/ghost-stories/run-story-tests.ts:
- Around line 29-50: The vitest invocation via executeCommand (variable
testProcess in run-story-tests.ts) can hang indefinitely; add a timeout (e.g.
VITEST_TIMEOUT) and ensure the run is bounded either by passing a timeout option
to executeCommand if it supports it or by wrapping testProcess in a Promise.race
with a timeoutPromise that rejects after VITEST_TIMEOUT (and handle that
rejection in the existing catch to set testFailureMessage). Reference
executeCommand, testProcess, and set a named constant VITEST_TIMEOUT for the
duration.
- Around line 1-9: In run-story-tests.ts replace the console.error call
(currently used around line 141) with the server-side logger: add an import
"logger" from 'storybook/internal/node-logger' at the top of the file and change
the console.error invocation(s) to logger.error (preserving the same message and
any error object), ensuring server-side logging follows the project's
node-logger usage.
- Around line 56-66: The code calls JSON.parse on resultsJson without error
handling; wrap the parse in a try-catch around JSON.parse(resultsJson)
(identifying resultsJson, testResults, outputFile) and on catch return the same
failure shape (success: false, duration, error) but set error to a descriptive
message including the parse exception message and that outputFile was
malformed/trimmed; optionally include a short snippet or first N chars of
resultsJson for debugging, and ensure no exception propagates from the function.
- Around line 140-142: Replace the direct console.error call in the catch block
of run-story-tests (the catch handling around running story tests) with the
Storybook server logger: import logger from 'storybook/internal/node-logger' at
the top if not present and call logger.error with a clear message and the caught
error object (preserving the current message "Error running story tests:" and
including the error variable) so server-side logging follows the coding
guideline.

In @code/core/src/telemetry/ecosystem-identifier.ts:
- Around line 76-98: The UI_LIBRARY_PACKAGES array contains a duplicate entry
for 'primereact'; remove the redundant 'primereact' string from the
UI_LIBRARY_PACKAGES constant so each package appears only once (update the
exported UI_LIBRARY_PACKAGES definition accordingly).
🧹 Nitpick comments (4)
code/core/src/telemetry/ecosystem-identifier.ts (1)

120-134: Consider adding helper functions for all package groups.

Only 4 of 7 package groups have helper functions (isStateManagementPackage, isStylingPackage, isRouterPackage, isI18nPackage). Consider adding helpers for the remaining groups (TEST_PACKAGES, DATA_FETCHING_PACKAGES, UI_LIBRARY_PACKAGES) to maintain API consistency.

➕ Add missing helper functions
export function isTestPackage(dependencyName: string): boolean {
  return matchesPackagePattern(dependencyName, TEST_PACKAGES);
}

export function isDataFetchingPackage(dependencyName: string): boolean {
  return matchesPackagePattern(dependencyName, DATA_FETCHING_PACKAGES);
}

export function isUILibraryPackage(dependencyName: string): boolean {
  return matchesPackagePattern(dependencyName, UI_LIBRARY_PACKAGES);
}
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts (1)

7-9: Remove unnecessary mock clearing.

The beforeEach block clears mocks, but this test file doesn't use any mocks. The extractCategorizedErrors function is pure and processes data without external dependencies. Remove this unnecessary setup.

♻️ Proposed fix
-  beforeEach(() => {
-    vi.clearAllMocks();
-  });
-
   describe('extractCategorizedErrors', () => {
code/core/src/core-server/utils/ghost-stories/run-story-tests.ts (1)

16-21: Consider cleanup of temporary test result files.

The function creates timestamped JSON files in the cache directory (test-results-${timestamp}.json) but never cleans them up. Over time, this could accumulate many files. Consider implementing a cleanup strategy, such as deleting files older than a certain threshold or removing the file after successful processing.

🧹 Example cleanup approach

After successfully reading and parsing the results:

// After line 65, once results are parsed successfully
try {
  await unlink(outputFile);
  logger.debug(`Cleaned up test results file: ${outputFile}`);
} catch (cleanupError) {
  logger.warn(`Failed to clean up test results file: ${outputFile}`, cleanupError);
}

Or implement a retention policy to delete old files when creating new ones.

code/core/src/core-server/utils/ghost-stories/get-candidates.ts (1)

164-166: Use template literal for consistency.

Line 165 uses string concatenation instead of a template literal, which is inconsistent with the logging style used elsewhere in this file.

✨ Use template literal
     const candidates = await getCandidatesForStorybook(files, sampleSize);
-    logger.debug('candidates files:' + files.length);
+    logger.debug(`candidates files: ${files.length}`);

     return {
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0cda5ae and fabaa0d.

📒 Files selected for processing (8)
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
  • code/core/src/core-server/utils/ghost-stories/types.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{js,jsx,ts,tsx,json,md,html,css,scss}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Format code using Prettier with yarn prettier --write <file>

Files:

  • code/core/src/core-server/utils/ghost-stories/types.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run ESLint checks using yarn lint:js:cmd <file> or the full command cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives to fix linting errors before committing

Files:

  • code/core/src/core-server/utils/ghost-stories/types.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Enable TypeScript strict mode across all packages

Files:

  • code/core/src/core-server/utils/ghost-stories/types.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx,js,jsx}: Export functions from modules if they need to be tested
Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/core/src/core-server/utils/ghost-stories/types.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use logger from storybook/internal/node-logger for server-side logging in Node.js code

Files:

  • code/core/src/core-server/utils/ghost-stories/types.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{test,spec}.{ts,tsx}: Test files should follow the naming pattern *.test.ts, *.test.tsx, *.spec.ts, or *.spec.tsx
Follow the spy mocking rules defined in .cursor/rules/spy-mocking.mdc for consistent mocking patterns with Vitest

Files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/spy-mocking.mdc)

**/*.test.{ts,tsx,js,jsx}: Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Use vi.mocked() to type and access the mocked functions in Vitest tests
Implement mock behaviors in beforeEach blocks in Vitest tests
Mock all required dependencies that the test subject uses
Each mock implementation should return a Promise for async functions in Vitest
Mock implementations should match the expected return type of the original function
Mock all required properties and methods that the test subject uses in Vitest tests
Avoid direct function mocking without vi.mocked() in Vitest tests
Avoid mock implementations outside of beforeEach blocks in Vitest tests
Avoid mocking without the spy: true option in Vitest tests
Avoid inline mock implementations within test cases in Vitest tests
Avoid mocking only a subset of required dependencies in Vitest tests
Mock at the highest level of abstraction needed in Vitest tests
Keep mock implementations simple and focused in Vitest tests
Use type-safe mocking with vi.mocked() in Vitest tests
Document complex mock behaviors in Vitest tests
Group related mocks together in Vitest tests

Files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{test,spec}.{ts,tsx,js,jsx}: Write meaningful unit tests that actually import and call the functions being tested, not just verify syntax patterns
Achieve high test coverage of business logic, aiming for 75%+ coverage of statements/lines
Cover all branches, conditions, edge cases, error paths, and different input variations in unit tests
Use vi.mock() to mock file system, loggers, and other external dependencies in tests

Files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
🧠 Learnings (19)
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking only a subset of required dependencies in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Group related mocks together in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid inline mock implementations within test cases in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Keep mock implementations simple and focused in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required properties and methods that the test subject uses in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Cover all branches, conditions, edge cases, error paths, and different input variations in unit tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mock implementations outside of `beforeEach` blocks in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Implement mock behaviors in `beforeEach` blocks in Vitest tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Write meaningful unit tests that actually import and call the functions being tested, not just verify syntax patterns

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-10-01T15:24:01.060Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32594
File: code/core/src/components/components/Popover/WithPopover.tsx:7-9
Timestamp: 2025-10-01T15:24:01.060Z
Learning: In the Storybook repository, "react-aria-components/patched-dist/*" (e.g., "react-aria-components/patched-dist/Dialog", "react-aria-components/patched-dist/Popover", "react-aria-components/patched-dist/Tooltip") are valid import paths created by a patch applied to the react-aria-components package. These imports should not be flagged as broken or invalid until a maintainer explicitly states they are no longer acceptable.

Applied to files:

  • code/core/src/telemetry/ecosystem-identifier.ts
📚 Learning: 2025-11-05T09:38:47.712Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.

Applied to files:

  • code/core/src/telemetry/ecosystem-identifier.ts
  • code/core/src/core-server/utils/ghost-stories/get-candidates.ts
  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required dependencies that the test subject uses

Applied to files:

  • code/core/src/telemetry/ecosystem-identifier.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Export functions from modules if they need to be tested

Applied to files:

  • code/core/src/telemetry/ecosystem-identifier.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Each mock implementation should return a Promise for async functions in Vitest

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Use `vi.mock()` to mock file system, loggers, and other external dependencies in tests

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx} : Use `logger` from `storybook/internal/node-logger` for server-side logging in Node.js code

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to code/{renderers}/**/*.{ts,tsx,js,jsx} : Use `logger` from `storybook/internal/client-logger` for client-side logging in browser code

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Do not use `console.log`, `console.warn`, or `console.error` directly unless in isolated files where importing loggers would significantly increase bundle size

Applied to files:

  • code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
🧬 Code graph analysis (4)
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts (2)
code/core/src/core-server/utils/ghost-stories/types.ts (1)
  • StoryTestResult (1-6)
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts (1)
  • extractCategorizedErrors (240-285)
code/core/src/core-server/utils/ghost-stories/get-candidates.ts (1)
code/core/src/core-server/utils/ghost-stories/component-analyzer.ts (1)
  • getComponentComplexity (19-34)
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts (2)
code/core/src/telemetry/ecosystem-identifier.ts (4)
  • isStateManagementPackage (120-122)
  • isRouterPackage (128-130)
  • isStylingPackage (124-126)
  • isI18nPackage (132-134)
code/core/src/core-server/utils/ghost-stories/types.ts (1)
  • StoryTestResult (1-6)
code/core/src/core-server/utils/ghost-stories/run-story-tests.ts (3)
code/core/src/core-server/utils/ghost-stories/types.ts (2)
  • GhostStoriesResponsePayload (22-38)
  • StoryTestResult (1-6)
code/core/src/common/utils/command.ts (1)
  • executeCommand (49-61)
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts (1)
  • extractCategorizedErrors (240-285)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
  • GitHub Check: nx
🔇 Additional comments (15)
code/core/src/telemetry/ecosystem-identifier.ts (7)

3-24: LGTM: Comprehensive test package patterns.

The test package patterns cover major testing frameworks and utilities appropriately.


26-44: LGTM: Comprehensive styling package patterns.

The styling package patterns appropriately cover CSS preprocessors, CSS-in-JS libraries, and UI frameworks.


46-59: LGTM: Comprehensive state management patterns.

The state management package patterns cover major state management solutions appropriately.


61-74: LGTM: Comprehensive data fetching patterns.

The data fetching package patterns appropriately cover HTTP clients, GraphQL clients, and data-fetching libraries.


100-111: LGTM: I18n and router package patterns are appropriate.

The patterns correctly use glob syntax to match scoped packages and variations of router package names.


1-1: No action required. The picomatch library is properly declared in code/core/package.json as a dependency with version "^2.3.0".


113-118: The picomatch API usage is correct. picomatch.isMatch(dependencyName, pattern) with version ^2.3.0 properly matches a dependency name against glob patterns, and the implementation correctly iterates through the patterns array passing individual pattern strings to the function.

code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts (1)

12-255: Excellent test coverage!

The test suite comprehensively covers all critical scenarios: empty results, unknown errors, specific provider categories (theme, state, router), aggregation with correct sorting, truncation, and filtering of non-failed tests. The tests validate both the structure and correctness of categorized error output.

code/core/src/core-server/utils/ghost-stories/types.ts (1)

1-38: Well-structured type definitions.

The interfaces are clear, well-organized, and properly aligned with their usage across the Ghost Stories feature. The type definitions provide good structure for test results, error categorization, and response payloads.

code/core/src/core-server/utils/ghost-stories/get-candidates.ts (2)

12-57: LGTM: Well-implemented AST-based validation.

The isValidCandidate function properly uses Babel's AST traversal to check for both JSX and exports, with early termination optimization (path.stop()) when both conditions are met. This is an efficient approach to filter component candidates.


64-112: LGTM: Smart complexity-based candidate selection.

The function intelligently prioritizes simple candidates (complexity < 0.3) for better test success rates, falling back to all analyzed candidates sorted by complexity when needed. The logging provides good visibility into the selection process.

code/core/src/core-server/utils/ghost-stories/categorize-render-errors.ts (4)

1-61: Well-structured error context building.

The error context construction properly normalizes messages and stacks for case-insensitive matching, and efficiently extracts dependency names from stack traces using regex. The regex pattern /\/deps\/([^/.]+)\.js/ appropriately captures dependency names from Vitest's bundled output paths.


76-159: Excellent priority-based categorization rules.

The rule-based categorization system is well-designed with clear priorities that resolve ambiguous cases correctly. Higher-priority rules (e.g., MODULE_IMPORT_ERROR at 100) take precedence over more general patterns. The combination of message matching and stack-based dependency detection provides robust error classification.


165-195: LGTM: Clean categorization with dependency extraction.

The categorizeError function properly applies rules by priority and extracts matched dependencies using ecosystem identifier helpers (isStateManagementPackage, isRouterPackage, etc.). This provides valuable telemetry about which packages are causing issues.


240-285: Solid aggregation logic with proper deduplication.

The extractCategorizedErrors function correctly:

  • Filters for failed tests with errors
  • Aggregates by category with counts
  • Tracks unique error messages separately from categories
  • Limits examples to 3 per category (truncated to 100 chars)
  • Sorts results by count (descending) for prioritization

The distinction between totalErrors (all failures) and uniqueErrorCount (distinct messages) provides useful metrics for telemetry.

Comment on lines +71 to +81
for (const file of files) {
let source: string;
try {
source = await readFile(file, 'utf-8');
// filter out non-React code or files without exports
if (!isValidCandidate(source)) {
continue;
}
} catch {
continue;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add error logging in catch block.

The catch block (lines 79-81) silently swallows all errors when reading or validating candidate files. This makes debugging difficult when files fail to process. At minimum, log the error at debug level to help troubleshoot issues.

📋 Add error logging
     try {
       source = await readFile(file, 'utf-8');
       // filter out non-React code or files without exports
       if (!isValidCandidate(source)) {
         continue;
       }
-    } catch {
+    } catch (error) {
+      logger.debug(`Skipping file ${file}: ${error instanceof Error ? error.message : String(error)}`);
       continue;
     }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @code/core/src/core-server/utils/ghost-stories/get-candidates.ts around lines
71 - 81, The catch block in the loop that reads candidate files is silently
swallowing errors; update the catch to log the error at debug level including
the file path (variable "file") and the caught error so failures in readFile or
isValidCandidate are visible; specifically, inside the catch after the
readFile/isValidCandidate try, call a debug logger (e.g., console.debug or the
module's logger) with a clear message referencing "file" and the caught error
before continuing.

Base automatically changed from yann/vitest-component-transformer to yann/ghost-stories-research January 9, 2026 11:50
@yannbf yannbf merged commit 5bb62fd into yann/ghost-stories-research Jan 9, 2026
9 of 13 checks passed
@yannbf yannbf deleted the yann/ghost-stories-flow branch January 9, 2026 11:53
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