-
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
Core: Add Ghost stories flow #33490
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Core: Add Ghost stories flow #33490
Conversation
|
View your CI Pipeline Execution ↗ for commit 340ecec
☁️ Nx Cloud last updated this comment at |
|
Caution Review failedThe pull request is closed. 📝 WalkthroughWalkthroughAdds 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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
✨ Finishing touches
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
Comment |
There was a problem hiding this 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:
- The regex patterns may match in non-declaration contexts (strings, comments, or within other identifiers).
- Brace counting doesn't account for braces in template literals, regex patterns, or comments.
- 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
countNonEmptyRuntimeLinesFor 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
executeGhostStoriesFlowfunction 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
isEmptyRenderfunction 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: hiddentemporarily during initializationConsider 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 intestSummary.The
testSummaryobject contains bothpassed/failed(lines 23-24) andpassingCount/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 cachedstorybookComponentTestPathson line 334.
storybookComponentTestPathsis computed once at line 115, butgetComponentTestPaths()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
storybookComponentTestPathsto 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.2for 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 everycategorizeErrorinvocation. 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
📒 Files selected for processing (20)
code/addons/a11y/src/preview.tsxcode/addons/vitest/src/vitest-plugin/index.tscode/core/src/core-events/index.tscode/core/src/core-server/presets/common-preset.tscode/core/src/core-server/server-channel/ghost-stories-channel.test.tscode/core/src/core-server/server-channel/ghost-stories-channel.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/test-annotations.tscode/core/src/core-server/utils/ghost-stories/types.tscode/core/src/csf/core-annotations.tscode/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsxcode/core/src/manager/globals/exports.tscode/core/src/telemetry/index.tscode/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.mdcfor consistent mocking patterns with Vitest
Files:
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/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}: Usevi.mock()with thespy: trueoption for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Usevi.mocked()to type and access the mocked functions in Vitest tests
Implement mock behaviors inbeforeEachblocks 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 withoutvi.mocked()in Vitest tests
Avoid mock implementations outside ofbeforeEachblocks in Vitest tests
Avoid mocking without thespy: trueoption 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 withvi.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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.tscode/core/src/telemetry/index.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/core/src/csf/core-annotations.tscode/addons/vitest/src/vitest-plugin/index.tscode/core/src/core-server/server-channel/ghost-stories-channel.test.tscode/core/src/core-server/server-channel/ghost-stories-channel.tscode/core/src/core-events/index.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.tscode/core/src/core-server/utils/ghost-stories/types.tscode/core/src/telemetry/types.tscode/addons/a11y/src/preview.tsxcode/core/src/core-server/utils/ghost-stories/test-annotations.tscode/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsxcode/core/src/core-server/presets/common-preset.tscode/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 commandcross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directivesto fix linting errors before committing
Files:
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.tscode/core/src/telemetry/index.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/core/src/csf/core-annotations.tscode/addons/vitest/src/vitest-plugin/index.tscode/core/src/core-server/server-channel/ghost-stories-channel.test.tscode/core/src/core-server/server-channel/ghost-stories-channel.tscode/core/src/core-events/index.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.tscode/core/src/core-server/utils/ghost-stories/types.tscode/core/src/telemetry/types.tscode/addons/a11y/src/preview.tsxcode/core/src/core-server/utils/ghost-stories/test-annotations.tscode/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsxcode/core/src/core-server/presets/common-preset.tscode/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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.tscode/core/src/telemetry/index.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/core/src/csf/core-annotations.tscode/addons/vitest/src/vitest-plugin/index.tscode/core/src/core-server/server-channel/ghost-stories-channel.test.tscode/core/src/core-server/server-channel/ghost-stories-channel.tscode/core/src/core-events/index.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.tscode/core/src/core-server/utils/ghost-stories/types.tscode/core/src/telemetry/types.tscode/addons/a11y/src/preview.tsxcode/core/src/core-server/utils/ghost-stories/test-annotations.tscode/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsxcode/core/src/core-server/presets/common-preset.tscode/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 useconsole.log,console.warn, orconsole.errordirectly 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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.tscode/core/src/telemetry/index.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/core/src/csf/core-annotations.tscode/addons/vitest/src/vitest-plugin/index.tscode/core/src/core-server/server-channel/ghost-stories-channel.test.tscode/core/src/core-server/server-channel/ghost-stories-channel.tscode/core/src/core-events/index.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.tscode/core/src/core-server/utils/ghost-stories/types.tscode/core/src/telemetry/types.tscode/addons/a11y/src/preview.tsxcode/core/src/core-server/utils/ghost-stories/test-annotations.tscode/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsxcode/core/src/core-server/presets/common-preset.tscode/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
Usevi.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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/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
loggerfromstorybook/internal/node-loggerfor server-side logging in Node.js code
Files:
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.tscode/core/src/telemetry/index.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/core/src/csf/core-annotations.tscode/addons/vitest/src/vitest-plugin/index.tscode/core/src/core-server/server-channel/ghost-stories-channel.test.tscode/core/src/core-server/server-channel/ghost-stories-channel.tscode/core/src/core-events/index.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.tscode/core/src/core-server/utils/ghost-stories/types.tscode/core/src/telemetry/types.tscode/addons/a11y/src/preview.tsxcode/core/src/core-server/utils/ghost-stories/test-annotations.tscode/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsxcode/core/src/core-server/presets/common-preset.tscode/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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/core/src/csf/core-annotations.tscode/addons/vitest/src/vitest-plugin/index.tscode/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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/addons/vitest/src/vitest-plugin/index.tscode/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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/addons/vitest/src/vitest-plugin/index.tscode/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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/addons/vitest/src/vitest-plugin/index.tscode/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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/addons/vitest/src/vitest-plugin/index.tscode/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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/addons/vitest/src/vitest-plugin/index.tscode/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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/addons/vitest/src/vitest-plugin/index.tscode/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.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/addons/vitest/src/vitest-plugin/index.tscode/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.tscode/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.tscode/core/src/core-server/utils/ghost-stories/get-candidates.test.tscode/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.tscode/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.tscode/core/src/core-server/utils/ghost-stories/test-annotations.tscode/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.tscode/addons/vitest/src/vitest-plugin/index.tscode/addons/a11y/src/preview.tsxcode/core/src/core-server/utils/ghost-stories/test-annotations.tscode/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsxcode/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.tscode/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.tscode/addons/a11y/src/preview.tsxcode/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.tscode/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.tscode/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 theEventTypeunion 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
initGhostStoriesChannelfollows 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
!isGhostStoriesto 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
hasRunGhostStoriesFlowref 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
getComponentComplexityfunction 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.firstChildwhich could benullor may not be anHTMLElement. TheisEmptyRenderfunction expects anHTMLElementforgetComputedStyleto 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. TheGHOST_STORIES_REQUESTandGHOST_STORIES_RESPONSEevents are properly sourced through the generator. Thegenerate-source-files.tsscript bundlesruntime.tswhich imports fromcore-events/index.ts—where these events are defined—and automatically includes them in the generatedexports.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
StoryTestResultinterface 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
executeCommandandtelemetrycalls 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 fromSTORYBOOK_COMPONENT_PATHSand handles the semicolon-delimited format. Thefilter(Boolean)correctly handles trailing separators or empty segments.
358-369: LGTM - Ghost Stories global integration.The
ghostStories.enabledglobal is correctly set based on the presence ofSTORYBOOK_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
isValidCandidatefunction correctly uses early termination viapath.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_CATEGORIESconstant provides a comprehensive set of categories covering common React rendering issues (providers, hooks, modules, portals).
292-329: LGTM - Clean error aggregation implementation.The
extractUniqueCategorizedErrorsfunction 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.
code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
Outdated
Show resolved
Hide resolved
code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
Outdated
Show resolved
Hide resolved
| // 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; | ||
| // } |
There was a problem hiding this comment.
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.
| vi.mock('node:fs/promises'); | ||
| vi.mock('glob'); | ||
| vi.mock('storybook/internal/node-logger'); | ||
| vi.mock('./component-analyzer'); |
There was a problem hiding this comment.
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.
| 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
code/core/src/telemetry/index.ts
Outdated
| // TODO: DO NOT MERGE WITH THIS! IT'S FOR DEBUGGING PURPOSES ONLY! | ||
| console.log('telemetry ', { eventType, payload, options }); | ||
| return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| // 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.
Package BenchmarksCommit: The following packages have significant changes to their size or dependencies:
|
| 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 |
There was a problem hiding this 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 pathShould 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
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
There was a problem hiding this 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.
There was a problem hiding this 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 usingawaiterror handling for cache.set.If
cache.setfails, 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 inimportCount(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
importCountfromnonEmptyLines: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.testResultsis 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 usingErrorCategoryenum and addingmatchedDependencies.Based on the snippet from
categorize-render-errors.ts(lines 314-318), the actual categorized errors includematchedDependencies: string[]. This field is missing fromClassifiedError, which may cause data loss when serializing. Also,categorycould use a stricter type if anErrorCategoryenum 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
📒 Files selected for processing (6)
code/core/src/core-server/server-channel/ghost-stories-channel.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.test.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/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 commandcross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directivesto fix linting errors before committing
Files:
code/core/src/core-server/server-channel/ghost-stories-channel.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/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.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/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 useconsole.log,console.warn, orconsole.errordirectly unless in isolated files where importing loggers would significantly increase bundle size
Files:
code/core/src/core-server/server-channel/ghost-stories-channel.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/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
loggerfromstorybook/internal/node-loggerfor server-side logging in Node.js code
Files:
code/core/src/core-server/server-channel/ghost-stories-channel.tscode/core/src/core-server/utils/ghost-stories/component-analyzer.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/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.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/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_RESPONSEin 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: Theinoperator check is correct and appropriate for themetadata.addonsstructure.The
metadata.addonsfield is typed asRecord<string, StorybookAddon>(an object with addon names as keys), not an array. The check'@storybook/addon-vitest' in metadata.addonscorrectly uses theinoperator 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
successRateWithoutEmptyRendermetric 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
GhostStoriesResponsePayloadprovides a clear contract for the test results, with optionaltestSummaryfor successful runs and optionalerrorfor failures. The inline type fortestSummaryis comprehensive.code/core/src/core-server/utils/ghost-stories/get-candidates.ts (2)
12-57: Efficient AST traversal with early exit.The
isValidCandidatefunction correctly usespath.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.
code/core/src/core-server/utils/ghost-stories/get-candidates.ts
Outdated
Show resolved
Hide resolved
code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
Outdated
Show resolved
Hide resolved
code/core/src/core-server/utils/ghost-stories/run-story-tests.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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 unnecessaryvi.clearAllMocks()call.The
beforeEachhook 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 nesteddescribeblock with its ownbeforeEach.The inline mock implementation (lines 170-173) deviates from the coding guideline to implement mock behaviors in
beforeEachblocks. For test-specific mock overrides, a nesteddescribewith its ownbeforeEachimproves 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
📒 Files selected for processing (9)
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/telemetry/ecosystem-identifier.tscode/core/src/telemetry/get-known-packages.test.tscode/core/src/telemetry/get-known-packages.tscode/core/src/telemetry/storybook-metadata.test.tscode/core/src/telemetry/storybook-metadata.tscode/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.mdcfor consistent mocking patterns with Vitest
Files:
code/core/src/telemetry/get-known-packages.test.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/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}: Usevi.mock()with thespy: trueoption for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Usevi.mocked()to type and access the mocked functions in Vitest tests
Implement mock behaviors inbeforeEachblocks 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 withoutvi.mocked()in Vitest tests
Avoid mock implementations outside ofbeforeEachblocks in Vitest tests
Avoid mocking without thespy: trueoption 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 withvi.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.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/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.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/get-known-packages.tscode/core/src/telemetry/storybook-metadata.tscode/core/src/telemetry/types.tscode/core/src/telemetry/ecosystem-identifier.tscode/core/src/telemetry/storybook-metadata.test.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/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 commandcross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directivesto fix linting errors before committing
Files:
code/core/src/telemetry/get-known-packages.test.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/get-known-packages.tscode/core/src/telemetry/storybook-metadata.tscode/core/src/telemetry/types.tscode/core/src/telemetry/ecosystem-identifier.tscode/core/src/telemetry/storybook-metadata.test.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/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.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/get-known-packages.tscode/core/src/telemetry/storybook-metadata.tscode/core/src/telemetry/types.tscode/core/src/telemetry/ecosystem-identifier.tscode/core/src/telemetry/storybook-metadata.test.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/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 useconsole.log,console.warn, orconsole.errordirectly unless in isolated files where importing loggers would significantly increase bundle size
Files:
code/core/src/telemetry/get-known-packages.test.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/get-known-packages.tscode/core/src/telemetry/storybook-metadata.tscode/core/src/telemetry/types.tscode/core/src/telemetry/ecosystem-identifier.tscode/core/src/telemetry/storybook-metadata.test.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/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
Usevi.mock()to mock file system, loggers, and other external dependencies in tests
Files:
code/core/src/telemetry/get-known-packages.test.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/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
loggerfromstorybook/internal/node-loggerfor server-side logging in Node.js code
Files:
code/core/src/telemetry/get-known-packages.test.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/get-known-packages.tscode/core/src/telemetry/storybook-metadata.tscode/core/src/telemetry/types.tscode/core/src/telemetry/ecosystem-identifier.tscode/core/src/telemetry/storybook-metadata.test.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/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.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/ecosystem-identifier.tscode/core/src/telemetry/storybook-metadata.test.tscode/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.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/storybook-metadata.test.tscode/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.tscode/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.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/storybook-metadata.test.tscode/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.tscode/core/src/telemetry/ecosystem-identifier.tscode/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.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/storybook-metadata.test.tscode/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.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/storybook-metadata.test.tscode/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.tscode/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.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/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.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/storybook-metadata.test.tscode/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.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/storybook-metadata.test.tscode/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.tscode/core/src/telemetry/storybook-metadata.test.tscode/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.tscode/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.tscode/core/src/telemetry/storybook-metadata.test.tscode/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.tscode/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
buildErrorContextfunction correctly:
- Normalizes message and stack for case-insensitive matching
- Extracts dependency names from stack traces using the
/deps/{name}.jspattern- 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
extractCategorizedErrorsfunction 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:
KnownPackagesListimport aligns with the new ecosystem package analysisghost-storiesevent type follows the existing union pattern- Optional
knownPackagesfield appropriately replacestestPackageswith richer categorizationAlso applies to: 43-44, 81-81
code/core/src/telemetry/get-known-packages.test.ts (2)
54-123: Clarify expected behavior:emotionpackage not matching@emotion/*pattern.Line 60 includes
emotion: '11.0.0'in the test dependencies, but the expectedstylingPackages(lines 87-90) excludes it. This is correct sinceSTYLING_PACKAGEScontains@emotion/*(scoped pattern) but not the unscopedemotionpackage.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.mockwithspy: trueand implements mock behaviors inbeforeEach. 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
knownPackagesintegration path. The mock data structure aligns withKnownPackagesListand the assertion confirms proper propagation throughcomputeStorybookMetadata.
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, andget-known-packagescorrectly usevi.mockwithspy: true, and implementations are placed inbeforeEachas 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
analyzeEcosystemPackagescall 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.coerceappropriately normalizes complex version strings.
93-112: Intentional asymmetry in version resolution?
testPackagesresolves actual installed versions viagetActualPackageVersion(lines 93-105), while other categories (lines 107-112) use declared versions frompackage.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
matchesPackagePatternutility correctly leveragespicomatch.isMatchfor 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 constfor type safety. The helper predicates follow a consistent delegation pattern.
84-84: > Likely an incorrect or invalid review comment.
code/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.ts
Outdated
Show resolved
Hide resolved
|
|
||
| return enhancedResponse; | ||
| } catch (error) { | ||
| console.error('Error running story tests:', error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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).
There was a problem hiding this 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
beforeEachblock clears mocks, but this test file doesn't use any mocks. TheextractCategorizedErrorsfunction 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
📒 Files selected for processing (8)
code/core/src/core-server/server-channel/ghost-stories-channel.test.tscode/core/src/core-server/server-channel/ghost-stories-channel.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/core/src/core-server/utils/ghost-stories/run-story-tests.tscode/core/src/core-server/utils/ghost-stories/types.tscode/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.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/ecosystem-identifier.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.tscode/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 commandcross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directivesto fix linting errors before committing
Files:
code/core/src/core-server/utils/ghost-stories/types.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/ecosystem-identifier.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.tscode/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.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/ecosystem-identifier.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.tscode/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 useconsole.log,console.warn, orconsole.errordirectly unless in isolated files where importing loggers would significantly increase bundle size
Files:
code/core/src/core-server/utils/ghost-stories/types.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/ecosystem-identifier.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.tscode/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
loggerfromstorybook/internal/node-loggerfor server-side logging in Node.js code
Files:
code/core/src/core-server/utils/ghost-stories/types.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.test.tscode/core/src/telemetry/ecosystem-identifier.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/core/src/core-server/utils/ghost-stories/categorize-render-errors.tscode/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.mdcfor 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}: Usevi.mock()with thespy: trueoption for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Usevi.mocked()to type and access the mocked functions in Vitest tests
Implement mock behaviors inbeforeEachblocks 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 withoutvi.mocked()in Vitest tests
Avoid mock implementations outside ofbeforeEachblocks in Vitest tests
Avoid mocking without thespy: trueoption 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 withvi.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
Usevi.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.tscode/core/src/telemetry/ecosystem-identifier.tscode/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.tscode/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.tscode/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.tscode/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.tscode/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.tscode/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.tscode/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.tscode/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.tscode/core/src/core-server/utils/ghost-stories/get-candidates.tscode/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
isValidCandidatefunction 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
categorizeErrorfunction 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
extractCategorizedErrorsfunction 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) anduniqueErrorCount(distinct messages) provides useful metrics for telemetry.
| 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; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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:
ghost-stories-channel(initGhostStoriesChannel) that listens forGHOST_STORIES_REQUESTevents, 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)code/core/src/core-server/presets/common-preset.ts) [1] [2]Core events and plugin wiring:
GHOST_STORIES_REQUESTandGHOST_STORIES_RESPONSE, and exported them for use in the system. (code/core/src/core-events/index.ts) [1] [2]ghostStoriesglobal. 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:
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:
Manual testing
Caution
This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!
Documentation
MIGRATION.MD
Checklist for Maintainers
When this PR is ready for testing, make sure to add
ci:normal,ci:mergedorci:dailyGH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found incode/lib/cli-storybook/src/sandbox-templates.tsMake 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 runningnpx [email protected] sandboxor in an existing project withnpx [email protected] upgrade.More information
0.0.0-pr-33490-sha-0cda5ae0yann/ghost-stories-flow0cda5ae01767912195)To request a new release of this pull request, mention the
@storybookjs/coreteam.core team members can create a new canary release here or locally with
gh workflow run --repo storybookjs/storybook publish.yml --field pr=33490Summary by CodeRabbit
New Features
Improvements
Tests
✏️ Tip: You can customize this high-level summary in your review settings.