-
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
WIP: Story inspector #32565
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
base: next
Are you sure you want to change the base?
WIP: Story inspector #32565
Conversation
…ories Co-authored-by: yannbf <[email protected]>
WalkthroughAdds a new Storybook addon “Story Inspector” with build, runtime, and documentation assets. Introduces a Vite plugin that injects component file-path metadata into JSX. Registers addon entries (manager, preview, preset), a React tool UI, and a hook to scan rendered components, match them to the story index, and emit highlights with context menus. Implements manager-side flows to navigate to stories, open in editor, and create stories programmatically. Wires addon into Storybook config (main.ts, preview.tsx), version map, build system, and package dependencies. Includes tests for the matcher utilities and Vite plugin. Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Toolbar as Storybook Toolbar (Tool)
participant Manager as Addon Manager
participant Preview as Preview (Addon Decorator/Hook)
participant Iframe as Preview Iframe (Canvas)
participant Core as Storybook Core APIs
User->>Toolbar: Toggle Story Inspector (global)
Toolbar-->>Preview: Update globals[PARAM_KEY]
Preview->>Iframe: Scan DOM for [data-sb-component-path]
Preview->>Core: Request Story Index
Core-->>Preview: Story Index
Preview->>Preview: Match components vs. index
Preview-->>Manager: Emit highlight configs (with/without stories)
User->>Iframe: Click highlight menu (Navigate / Create / Open in editor)
Iframe-->>Manager: Event (navigate/create/open)
alt Navigate to story
Manager->>Core: selectStory(storyId)
else Create story
Manager->>Core: createStory(componentPath)
Manager->>Core: selectStory(newStoryId) (retry)
Manager->>Core: fetch argTypes, save defaults
else Open in editor
Manager->>Core: openInEditor(filePath)
end
sequenceDiagram
autonumber
participant Dev as Developer
participant Vite as Vite (Build)
participant Plugin as componentPathInjectorPlugin
participant Bundle as Built Code
participant Browser as Browser
participant Iframe as Preview Iframe
Dev->>Vite: Start Storybook (Vite)
Vite->>Plugin: transform TSX/JSX (component files)
Plugin->>Plugin: Inject data-sb-component-path="<relative path>"
Plugin-->>Vite: Transformed code
Vite-->>Bundle: Bundle output
Browser->>Iframe: Render story
Iframe->>Iframe: Elements carry data-sb-component-path
Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
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: 12
🧹 Nitpick comments (21)
code/addons/story-inspector/USAGE.md (1)
60-69: Clarify “Create story” capability and prerequisitesSpell out that automated story creation requires dev/build integration (and won’t run on hosted Storybook).
-When you click "Create story" on an orange-highlighted component: -1. The addon automatically creates a new story file -2. Generates basic story structure with sensible defaults -3. Navigates you to the newly created story -4. Shows a success notification +When you click "Create story" on an orange-highlighted component (in local dev with the preset enabled): +1. The addon triggers story file creation via the dev integration +2. Generates a basic story with sensible defaults +3. Navigates to the newly created story +4. Shows a success notification + +Note: Automated file creation is not available on hosted Storybook builds without write access or the preset.code/addons/story-inspector/package.json (1)
31-43: Export types for manager/preset entrypointsAdd type declarations for manager and preset to improve DX and TS resolution.
"exports": { ".": { "types": "./dist/index.d.ts", "default": "./dist/index.js" }, - "./manager": "./dist/manager.js", + "./manager": { + "types": "./dist/manager.d.ts", + "default": "./dist/manager.js" + }, "./package.json": "./package.json", - "./preset": "./dist/preset.js", + "./preset": { + "types": "./dist/preset.d.ts", + "default": "./dist/preset.js" + }, "./preview": { "types": "./dist/preview.d.ts", "default": "./dist/preview.js" } },code/addons/story-inspector/README.md (1)
38-42: Align README claims with current behavior.The manager flow does not yet implement an automatic navigation step after triggering story creation—the new story selection currently races and may silently fail. Until the logic reliably navigates (see manager.tsx comment), please soften the documentation so it doesn’t promise an outcome we don’t yet guarantee.
code/addons/story-inspector/src/components/StoryInspectorTool.tsx (1)
35-49: Guard against inline layout styles.Relying on inline absolute positioning inside
<IconButton>breaks if the host button isn’tposition: relative(which isn’t guaranteed). This can misplace or hide the badge in themes that reset button layout.Move these styles into a class that ensures a positioned container or wrap the badge in a relatively positioned element before applying absolute offsets.
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts (2)
12-14: Avoid global document reassignment in tests.Overwriting
global.documentfor the whole module introduces hidden coupling between tests. Prefer stubbing only the members you need (e.g.vi.spyOn(document, 'getElementById')) or usevi.stubGlobalwith proper teardown to keep each test isolated.
103-130: Mock DOM objects with DOM-like shape.
mockElement1/2/3supply onlygetAttribute, butfindComponentsInDOMlater readstagNamewhen generating selectors. Provide a minimal DOM-like object ({ tagName: 'DIV', getAttribute: ... }) so failures surface in tests instead of at runtime.code/addons/story-inspector/build-config.ts (2)
11-14: Confirm we really want to skip DTS for manager entry.Turning off type generation for
./managermeans downstream TypeScript consumers won’t see declarations for the public manager API. If the entry exports runtime helpers, consider leavingdtson (default) unless there’s a concrete reason to disable it.
21-25: Revisit preset DTS disablement.The preset is a node entry that likely exports config hooks; disabling declarations makes authoring custom configs harder. Unless we hit a specific DTS bug, we should keep typings available.
code/addons/story-inspector/src/manager.tsx (3)
107-121: Required-arg defaulting is too naive.Blindly defaulting to
null/true/42produces invalid saves for rich arg shapes (arrays, enums, functions) and often triggers validation errors. Reuse the defaults Storybook already computes (e.g. leverageargType.defaultValueor omit unsatisfied args) instead of guessing values.
149-158: Avoid hard-coded emoji spans in notifications.Using raw emoji spans bypasses theming and accessibility hooks. Reuse Storybook’s icon components (e.g.
Icons) so notifications stay consistent across themes.
170-178: Include actionable error context.
subHeadlinecurrently prints the raw error message, which is often generic. Surface the component path and suggest manual steps (open the modal, check logs) so users aren’t left guessing.code/addons/story-inspector/src/index.ts (1)
5-5: Rename the re-export to avoid ambiguity with the addon nameExporting the Vite plugin as storyInspector can be confusing given the addon’s identity. Prefer a clearer name like viteStoryInspectorPlugin.
Apply:
-export { componentPathInjectorPlugin as storyInspector } from './utils/vite-plugin'; +export { componentPathInjectorPlugin as viteStoryInspectorPlugin } from './utils/vite-plugin';code/addons/story-inspector/src/utils/vite-plugin.ts (4)
12-22: Harden ID filtering: strip Vite query suffixes; avoid Vue/Svelte unless parser supports themVite passes IDs with
?query. Also,babelParsehere won’t handle Vue/Svelte SFCs. Limit to TSX/JSX by default and normalize ID before extension checks.Apply:
- const filter = (id: string) => { - // Include React/Vue/Svelte component files - const includeExtensions = ['.jsx', '.tsx', '.js', '.ts', '.vue', '.svelte']; - const hasIncludedExt = includeExtensions.some((ext) => id.endsWith(ext)); + const filter = (rawId: string) => { + const id = rawId.split('?')[0]; + // Include React component files by default; expand when dedicated parsers are added + const includeExtensions = ['.jsx', '.tsx']; + const hasIncludedExt = includeExtensions.some((ext) => id.endsWith(ext)); // Exclude certain patterns - const excludePatterns = ['node_modules', '.stories.', '.spec.', '.test.', 'dist', 'build']; + const excludePatterns = ['node_modules', '.stories.', '.spec.', '.test.', 'dist', 'build']; const isExcluded = excludePatterns.some((pattern) => id.includes(pattern)); return hasIncludedExt && !isExcluded; };If you want .js/.ts support, keep them but rely on isComponentFile to skip non-JSX.
70-74: Normalize paths relative to the monorepo /code/ segment when present; otherwise use cwd-relativeCurrent logic only strips cwd. Make it robust and cross‑platform.
Apply:
- const root = process.cwd(); - let normalizedPath = filePath.replace(root, ''); - normalizedPath = normalizedPath.startsWith('./') ? normalizedPath : `.${normalizedPath}`; + const path = require('node:path'); + const cwd = process.cwd(); + const idNoQuery = filePath.split('?')[0]; + const parts = idNoQuery.split(path.sep); + const codeIdx = parts.lastIndexOf('code'); + let rel = + codeIdx >= 0 ? parts.slice(codeIdx + 1).join(path.posix.sep) : path.relative(cwd, idNoQuery); + if (!rel.startsWith('.')) rel = `./${rel}`; + const normalizedPath = rel.replace(/\\/g, '/');
176-180: Make warnings opt‑in or silenced in testsUnconditional console.warn can spam logs. Respect a silent option.
Apply:
- console.warn('Story Inspector: Failed to parse code with AST, skipping transformation:', error); + if (!options.silent) { + console.warn( + 'Story Inspector: Failed to parse code with AST, skipping transformation:', + error + ); + }
80-164: Avoid any casts by building proper Babel JSX nodesUse @babel/types builders to create attributes instead of casting objects to any.
Example (outside the shown range):
import * as t from '@babel/types'; // ... node.attributes.push( t.jsxAttribute(t.jsxIdentifier(COMPONENT_PATH_ATTRIBUTE), t.stringLiteral(normalizedPath)) );code/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts (1)
131-138: Loosen brittle formatting assertions around type annotationsBabel printing may change whitespace/punctuation across versions. Use regex or more permissive contains to avoid flaky tests.
Apply:
- expect(result?.code).toContain('FC<React.PropsWithChildren<{layout: string;}>>'); + expect(result?.code).toMatch(/FC<React\.PropsWithChildren<\{\s*layout:\s*string;?\s*\}>>/);code/addons/story-inspector/src/hooks/useStoryInspector.ts (2)
97-122: Reduce repeated work when generating per-item selectorsYou call generateSelectorsForComponents([component])[0] multiple times. Compute once per component inside the map for readability and perf.
Example:
menu: withStories.map<HighlightMenuItem[]>((component) => { const [selector] = generateSelectorsForComponents([component]); return [ { /* ... */, selectors: [selector] }, { /* ... */, selectors: [selector] }, { /* ... */, selectors: [selector] }, ]; }),
130-169: Same selector precompute for withoutStories menuMirror the selector precompute to avoid redundant calls.
code/addons/story-inspector/src/utils/story-matcher.ts (2)
60-86: Avoid O(n·m) scans by indexing entries by normalized componentPathCurrent find() over Object.values for each component can be costly. Build a map once.
Apply:
-export function checkComponentsAgainstIndex( - components: ComponentInfo[], - storyIndex: StoryIndex['entries'] -): ComponentInfo[] { - const entries = storyIndex || {}; - - return components.map((component) => { - // Find matching story entries by comparing componentPath - const matchingEntry = Object.values(entries).find((entry) => { - // Normalize paths for comparison - const entryPath = (entry as any).componentPath?.replace(/\\/g, '/'); - const componentPath = component.componentPath.replace(/\\/g, '/'); - return entryPath === componentPath; - }); +export function checkComponentsAgainstIndex( + components: ComponentInfo[], + storyIndex: StoryIndex['entries'] +): ComponentInfo[] { + const entries = storyIndex || {}; + const byPath = new Map<string, IndexEntry>(); + for (const entry of Object.values(entries)) { + const p = (entry as any).componentPath?.replace(/\\/g, '/'); + if (p) byPath.set(p, entry); + } + + return components.map((component) => { + const componentPath = component.componentPath.replace(/\\/g, '/'); + const matchingEntry = byPath.get(componentPath);
14-36: Optional: allow injection of a document/root for testing and flexibilityAccepting a root Document (defaulting to the preview iframe doc) would simplify testing and decouple DOM traversal.
Example signature:
export function findComponentsInDOM(rootDoc?: Document): ComponentInfo[] { /* ... */ }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
code/yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (27)
code/.storybook/main.ts(1 hunks)code/.storybook/preview.tsx(2 hunks)code/addons/story-inspector/README.md(1 hunks)code/addons/story-inspector/USAGE.md(1 hunks)code/addons/story-inspector/build-config.ts(1 hunks)code/addons/story-inspector/manager.js(1 hunks)code/addons/story-inspector/package.json(1 hunks)code/addons/story-inspector/preset.js(1 hunks)code/addons/story-inspector/preview.js(1 hunks)code/addons/story-inspector/project.json(1 hunks)code/addons/story-inspector/src/components/StoryInspectorTool.tsx(1 hunks)code/addons/story-inspector/src/constants/index.ts(1 hunks)code/addons/story-inspector/src/hooks/useStoryInspector.ts(1 hunks)code/addons/story-inspector/src/index.ts(1 hunks)code/addons/story-inspector/src/manager.tsx(1 hunks)code/addons/story-inspector/src/preset.ts(1 hunks)code/addons/story-inspector/src/preview.ts(1 hunks)code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts(1 hunks)code/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts(1 hunks)code/addons/story-inspector/src/utils/story-matcher.ts(1 hunks)code/addons/story-inspector/src/utils/vite-plugin.ts(1 hunks)code/addons/story-inspector/tsconfig.json(1 hunks)code/addons/story-inspector/vitest.config.ts(1 hunks)code/core/src/common/versions.ts(1 hunks)code/core/src/highlight/icons.ts(1 hunks)code/package.json(1 hunks)scripts/build/entry-configs.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Adhere to ESLint and Prettier rules across all JS/TS source files
Files:
code/addons/story-inspector/preset.jscode/addons/story-inspector/src/constants/index.tscode/addons/story-inspector/src/utils/__tests__/story-matcher.test.tscode/addons/story-inspector/src/index.tscode/addons/story-inspector/manager.jscode/addons/story-inspector/src/utils/story-matcher.tscode/addons/story-inspector/src/utils/vite-plugin.tscode/addons/story-inspector/src/hooks/useStoryInspector.tscode/addons/story-inspector/src/components/StoryInspectorTool.tsxcode/addons/story-inspector/build-config.tscode/addons/story-inspector/vitest.config.tscode/addons/story-inspector/preview.jscode/core/src/highlight/icons.tscode/core/src/common/versions.tscode/addons/story-inspector/src/preset.tscode/addons/story-inspector/src/preview.tsscripts/build/entry-configs.tscode/addons/story-inspector/src/manager.tsxcode/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts
**/README.md
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Update relevant README files when making significant changes
Files:
code/addons/story-inspector/README.md
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode
Files:
code/addons/story-inspector/src/constants/index.tscode/addons/story-inspector/src/utils/__tests__/story-matcher.test.tscode/addons/story-inspector/src/index.tscode/addons/story-inspector/src/utils/story-matcher.tscode/addons/story-inspector/src/utils/vite-plugin.tscode/addons/story-inspector/src/hooks/useStoryInspector.tscode/addons/story-inspector/src/components/StoryInspectorTool.tsxcode/addons/story-inspector/build-config.tscode/addons/story-inspector/vitest.config.tscode/core/src/highlight/icons.tscode/core/src/common/versions.tscode/addons/story-inspector/src/preset.tscode/addons/story-inspector/src/preview.tsscripts/build/entry-configs.tscode/addons/story-inspector/src/manager.tsxcode/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts
code/**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
code/**/*.{test,spec}.{ts,tsx}: Place all test files under the code/ directory
Name test files as *.test.ts, *.test.tsx, *.spec.ts, or *.spec.tsx
Files:
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.tscode/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts
**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/spy-mocking.mdc)
**/*.test.{ts,tsx,js,jsx}: Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Use vi.mocked() to type and access mocked functions
Implement mock behaviors in beforeEach blocks
Mock all required dependencies that the test subject uses
Mock implementations should be placed in beforeEach blocks
Each mock implementation should return a Promise for async functions
Mock implementations should match the expected return type of the original function
Use vi.mocked() to access and implement mock behaviors
Mock all required properties and methods that the test subject uses
Avoid direct function mocking without vi.mocked()
Avoid mock implementations outside of beforeEach blocks
Avoid mocking without the spy: true option
Avoid inline mock implementations within test cases
Avoid mocking only a subset of required dependencies
Mock at the highest level of abstraction needed
Keep mock implementations simple and focused
Use type-safe mocking with vi.mocked()
Document complex mock behaviors
Group related mocks together
Files:
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.tscode/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts
code/**/tsconfig*.json
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Keep TypeScript strict mode enabled; do not relax strict compiler options in tsconfig files
Files:
code/addons/story-inspector/tsconfig.json
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to test-storybooks/** : Maintain test configurations and assets under test-storybooks/ for Storybook testing
Learnt from: ndelangen
PR: storybookjs/storybook#32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.209Z
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.
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to test-storybooks/** : Maintain test configurations and assets under test-storybooks/ for Storybook testing
Applied to files:
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.tscode/addons/story-inspector/project.jsoncode/package.jsoncode/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts
📚 Learning: 2025-09-17T08:11:47.197Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.197Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors
Applied to files:
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
📚 Learning: 2025-09-17T08:11:47.197Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.197Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Group related mocks together
Applied to files:
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Implement mock behaviors in beforeEach blocks
Applied to files:
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required properties and methods that the test subject uses
Applied to files:
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use vi.mocked() to access and implement mock behaviors
Applied to files:
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid inline mock implementations within test cases
Applied to files:
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
📚 Learning: 2025-09-17T08:11:47.197Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.197Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Keep mock implementations simple and focused
Applied to files:
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking only a subset of required dependencies
Applied to files:
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mock implementations outside of beforeEach blocks
Applied to files:
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
📚 Learning: 2025-09-24T09:39:39.209Z
Learnt from: ndelangen
PR: storybookjs/storybook#32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.209Z
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/addons/story-inspector/src/index.tscode/addons/story-inspector/preview.jscode/addons/story-inspector/src/preview.tsscripts/build/entry-configs.tscode/addons/story-inspector/src/manager.tsx
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to code/**/tsconfig*.json : Keep TypeScript strict mode enabled; do not relax strict compiler options in tsconfig files
Applied to files:
code/addons/story-inspector/tsconfig.json
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Adhere to ESLint and Prettier rules across all JS/TS source files
Applied to files:
code/addons/story-inspector/tsconfig.json
📚 Learning: 2025-09-17T08:11:04.287Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursorrules:0-0
Timestamp: 2025-09-17T08:11:04.287Z
Learning: Applies to code/**/*.{test,spec}.{ts,tsx} : Name test files as *.test.ts, *.test.tsx, *.spec.ts, or *.spec.tsx
Applied to files:
code/addons/story-inspector/tsconfig.json
📚 Learning: 2025-09-18T20:51:06.618Z
Learnt from: Sidnioulz
PR: storybookjs/storybook#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/story-inspector/src/hooks/useStoryInspector.tscode/addons/story-inspector/src/components/StoryInspectorTool.tsxcode/addons/story-inspector/src/preview.ts
📚 Learning: 2025-09-18T20:51:06.618Z
Learnt from: Sidnioulz
PR: storybookjs/storybook#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/story-inspector/src/hooks/useStoryInspector.tscode/addons/story-inspector/src/preview.ts
📚 Learning: 2025-09-17T08:11:04.287Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursorrules:0-0
Timestamp: 2025-09-17T08:11:04.287Z
Learning: Applies to code/vitest.workspace.ts : Keep and use the Vitest workspace configuration at code/vitest.workspace.ts
Applied to files:
code/addons/story-inspector/vitest.config.ts
🧬 Code graph analysis (10)
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts (1)
code/addons/story-inspector/src/utils/story-matcher.ts (5)
ComponentInfo(5-11)checkComponentsAgainstIndex(60-86)groupComponentsByStoryStatus(89-94)findComponentsInDOM(14-57)generateSelectorsForComponents(97-104)
code/addons/story-inspector/src/utils/story-matcher.ts (3)
code/core/src/types/modules/indexer.ts (2)
IndexEntry(86-86)StoryIndex(172-175)code/addons/story-inspector/src/constants/index.ts (1)
COMPONENT_PATH_ATTRIBUTE(6-6)code/core/src/preview-api/modules/preview-web/PreviewWeb.mockdata.ts (1)
storyIndex(90-162)
code/addons/story-inspector/src/utils/vite-plugin.ts (2)
code/addons/story-inspector/src/index.ts (1)
componentPathInjectorPlugin(5-5)code/addons/story-inspector/src/constants/index.ts (1)
COMPONENT_PATH_ATTRIBUTE(6-6)
code/addons/story-inspector/src/hooks/useStoryInspector.ts (3)
code/core/src/manager-api/root.tsx (3)
useGlobals(478-486)useChannel(326-336)useStorybookState(290-293)code/addons/story-inspector/src/constants/index.ts (4)
PARAM_KEY(3-3)EVENTS(13-16)HIGHLIGHT_ID_WITH_STORIES(9-9)HIGHLIGHT_ID_WITHOUT_STORIES(10-10)code/addons/story-inspector/src/utils/story-matcher.ts (5)
ComponentInfo(5-11)findComponentsInDOM(14-57)checkComponentsAgainstIndex(60-86)groupComponentsByStoryStatus(89-94)generateSelectorsForComponents(97-104)
code/addons/story-inspector/src/components/StoryInspectorTool.tsx (4)
code/core/src/manager-api/root.tsx (1)
useGlobals(478-486)code/addons/story-inspector/src/constants/index.ts (1)
PARAM_KEY(3-3)code/addons/story-inspector/src/hooks/useStoryInspector.ts (1)
useStoryInspector(24-197)code/core/src/components/index.ts (2)
components(93-93)IconButton(54-54)
code/addons/story-inspector/build-config.ts (1)
scripts/build/utils/entry-utils.ts (1)
BuildEntries(18-43)
code/addons/story-inspector/src/preset.ts (2)
code/addons/story-inspector/src/index.ts (1)
componentPathInjectorPlugin(5-5)code/addons/story-inspector/src/utils/vite-plugin.ts (1)
componentPathInjectorPlugin(10-53)
code/addons/story-inspector/src/preview.ts (1)
code/addons/story-inspector/src/constants/index.ts (1)
PARAM_KEY(3-3)
code/addons/story-inspector/src/manager.tsx (2)
code/addons/story-inspector/src/constants/index.ts (4)
ADDON_ID(1-1)TOOL_ID(2-2)PARAM_KEY(3-3)EVENTS(13-16)code/addons/story-inspector/src/components/StoryInspectorTool.tsx (1)
StoryInspectorTool(12-53)
code/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts (2)
code/addons/story-inspector/src/index.ts (1)
componentPathInjectorPlugin(5-5)code/addons/story-inspector/src/utils/vite-plugin.ts (1)
componentPathInjectorPlugin(10-53)
🔇 Additional comments (17)
code/addons/story-inspector/src/constants/index.ts (1)
1-16: LGTMConsistent IDs and const typing across addon identifiers/events.
code/.storybook/main.ts (1)
108-109: LGTMAddon is registered in the UI config alongside other core addons.
code/package.json (1)
118-119: LGTM; build and version wiring confirmed
Entry configs (scripts/build/entry-configs.ts) and core version map (core/src/common/versions.ts) include '@storybook/addon-story-inspector'.code/core/src/highlight/icons.ts (1)
2-5: Confirm new icon usage or remove dead entries
No references toplusoreditdetected; validate they’re consumed/rendered as intended or remove them.code/.storybook/preview.tsx (2)
15-15: Import of inspector addon is correct.Matches the pattern used by other addons in this file.
410-411: Preview-side registration LGTM
@storybook/addon-story-inspectoris present incode/.storybook/main.ts, so the preset/Vite plugin will run.scripts/build/entry-configs.ts (2)
14-16: New import is correct path-wise.No issues.
98-99: Naming consistency verified across build entry, versions map, and package name.code/addons/story-inspector/project.json (1)
1-31: Approve NX target wiring:yarn prepandyarn checkscripts are defined in package.json.code/core/src/common/versions.ts (1)
9-9: Approve version map entry
Entry in versions.ts matches the package.json version (10.0.0-beta.6).code/addons/story-inspector/preset.js (1)
1-1: Verify build output for story-inspector preset
package.jsonexports"./preset": "./dist/preset.js", butcode/addons/story-inspector/dist/preset.jsisn’t present. Ensure the build produces and includes this artifact.code/addons/story-inspector/manager.js (1)
1-1: Approve CJS re-export wrapper
package.json exports include./manager→./dist/manager.js, consistent with other addons.code/addons/story-inspector/src/preview.ts (1)
29-31: Initial globals should mirror a boolean toggle.Once the parameter is a boolean, keep
initialGlobalsaligned—no change needed, but double-check after adjusting the parameter so both exports stay consistent.code/addons/story-inspector/src/index.ts (2)
7-7: Double-check default export shape for preview annotationsReturning definePreviewAddon(addonAnnotations) is fine if consumers expect a function default export. Ensure this matches how other addons in this repo register preview annotations.
1-1: definePreviewAddon import is valid
definePreviewAddonis exported incode/core/src/csf/csf-factories.tsand re-exported fromcode/core/src/csf/index.ts, soimport { definePreviewAddon } from 'storybook/internal/csf'will resolve correctly.code/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts (2)
175-190: Verify path normalization expectation aligns with plugin behaviorAfter implementing code-directory-relative normalization, this should pass. If not, adjust either the plugin (preferred) or the expectation to match the agreed strategy.
6-11: LGTM: plugin metaName and enforce flags are correct for a pre-transform Vite plugin.
| @@ -0,0 +1 @@ | |||
| module.exports = require('./dist/preview'); | |||
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.
🧩 Analysis chain
CJS re-export wrapper LGTM.
Preview entry correctly proxies to dist/preview.
Confirm the exports map and dist artifact exist:
🏁 Script executed:
#!/bin/bash
jq -r '.exports?"./preview"' code/addons/story-inspector/package.json
rg -n "dist/preview" -g code/addons/story-inspector -SLength of output: 318
🏁 Script executed:
#!/bin/bash
# Verify "./preview" export entry
jq -r '.exports["./preview"]?' code/addons/story-inspector/package.json
# List any preview files in dist
ls -l code/addons/story-inspector/dist/preview*Length of output: 159
🏁 Script executed:
#!/bin/bash
echo "Dist directory listing:"
ls -R code/addons/story-inspector/dist || echo "dist directory absent"
echo "Searching for built preview files:"
rg -nE "preview\\.(js|d\\.ts|cjs|mjs)$" -g "code/addons/story-inspector/**"Length of output: 557
Add missing dist/preview.js (and types) before proxying
Export map defines "./preview" → ./dist/preview.js / preview.d.ts, but no code/addons/story-inspector/dist/preview.* files exist. Run the build and commit the generated artifacts.
🤖 Prompt for AI Agents
In code/addons/story-inspector/preview.js around line 1, the file is proxying to
./dist/preview but the built artifacts (dist/preview.js and preview.d.ts) are
missing; run the package build script (e.g., npm/yarn build or the specific
build command in the package.json) to generate dist/preview.js and
dist/preview.d.ts, add those generated files to the repository (git add/commit),
ensure .gitignore does not exclude them, and verify the package.json export map
correctly points to ./dist/preview.js and preview.d.ts so the proxy require
resolves.
| const foundComponents = findComponentsInDOM(); | ||
| const componentsWithStoryStatus = checkComponentsAgainstIndex(foundComponents, index as any); | ||
|
|
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.
Bug: Passing the full StoryIndex instead of entries map
checkComponentsAgainstIndex expects StoryIndex['entries'], but index is the whole object. This prevents any matches.
Apply:
- const componentsWithStoryStatus = checkComponentsAgainstIndex(foundComponents, index as any);
+ const componentsWithStoryStatus = checkComponentsAgainstIndex(foundComponents, index.entries);📝 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.
| const foundComponents = findComponentsInDOM(); | |
| const componentsWithStoryStatus = checkComponentsAgainstIndex(foundComponents, index as any); | |
| const foundComponents = findComponentsInDOM(); | |
| const componentsWithStoryStatus = checkComponentsAgainstIndex(foundComponents, index.entries); |
🤖 Prompt for AI Agents
In code/addons/story-inspector/src/hooks/useStoryInspector.ts around lines 43 to
45, the call passes the entire StoryIndex object to checkComponentsAgainstIndex
which expects the entries map; change the second argument to index.entries (or
properly typed as index.entries as Record<string, StoryIndexEntry> / any) so
checkComponentsAgainstIndex receives the entries map and can match components
correctly.
| const currentStoryEntry = index[currentStoryId]; | ||
|
|
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.
Bug: Accessing current story entry from index directly
index is a StoryIndex; entries are under index.entries.
Apply:
- const currentStoryEntry = index[currentStoryId];
+ const currentStoryEntry = index.entries[currentStoryId];📝 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.
| const currentStoryEntry = index[currentStoryId]; | |
| const currentStoryEntry = index.entries[currentStoryId]; |
🤖 Prompt for AI Agents
In code/addons/story-inspector/src/hooks/useStoryInspector.ts around lines
52-53, the code reads the current story entry from index using
index[currentStoryId] but index is a StoryIndex whose entries are under
index.entries; change the access to read from index.entries (e.g.,
index.entries[currentStoryId] or the appropriate lookup on entries) and handle
the case where index or index.entries may be undefined/null before accessing to
avoid runtime errors.
| api.on('storybook/navigate-to-story', (storyId: string) => { | ||
| api.selectStory(storyId); | ||
| }); |
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.
Use the payload object when handling navigation.
The highlight menu emits { storyId }, but this handler treats the payload as a string—selectStory ends up receiving { storyId: … }, so navigation silently fails. Destructure the payload before calling selectStory.
Apply this diff:
- api.on('storybook/navigate-to-story', (storyId: string) => {
- api.selectStory(storyId);
+ api.on('storybook/navigate-to-story', ({ storyId }: { storyId: string }) => {
+ api.selectStory(storyId);
});📝 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.
| api.on('storybook/navigate-to-story', (storyId: string) => { | |
| api.selectStory(storyId); | |
| }); | |
| api.on('storybook/navigate-to-story', ({ storyId }: { storyId: string }) => { | |
| api.selectStory(storyId); | |
| }); |
🤖 Prompt for AI Agents
In code/addons/story-inspector/src/manager.tsx around lines 20 to 22, the api.on
handler treats the event payload as a string but the emitter sends an object {
storyId }, so api.selectStory receives the whole object and navigation fails;
update the handler to accept the payload object (e.g., ({ storyId }) or payload
and destructure) and pass the extracted storyId to api.selectStory.
| api.on('storybook/open-editor', (file: string) => { | ||
| api.openInEditor({ file }); | ||
| }); |
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.
Supply file data when opening the editor.
The highlight menu never sends a payload for storybook/open-editor, so file is undefined and openInEditor becomes a no-op. Pass the component path through eventData when emitting the menu item so the handler can forward it.
🤖 Prompt for AI Agents
In code/addons/story-inspector/src/manager.tsx around lines 24 to 26, the
'storybook/open-editor' handler expects a string parameter but the highlight
menu emits no payload so file is undefined; change the handler signature to
accept the eventData object (e.g. (eventData) => ...) and call api.openInEditor
with eventData.file (or the correct property containing the component path).
Also update the menu emitter elsewhere to include the component path in
eventData when emitting 'storybook/open-editor' so the handler receives and
forwards the file path to api.openInEditor.
| export const viteFinal = async ( | ||
| config: import('vite').UserConfig, | ||
| options: Options | ||
| ): Promise<import('vite').UserConfig> => { | ||
| const plugins = config.plugins || []; | ||
|
|
||
| // Add our component path injector plugin | ||
| plugins.push(componentPathInjectorPlugin(options)); | ||
|
|
||
| return { | ||
| ...config, | ||
| plugins, | ||
| }; | ||
| }; |
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.
Normalize Vite plugins to an array to avoid runtime errors.
config.plugins can be a single PluginOption or nested arrays; pushing to it directly risks type errors and crashes.
Apply this diff:
@@
-import type { Options } from 'storybook/internal/types';
+import type { Options } from 'storybook/internal/types';
+import type { PluginOption, UserConfig } from 'vite';
@@
-export const viteFinal = async (
- config: import('vite').UserConfig,
- options: Options
-): Promise<import('vite').UserConfig> => {
- const plugins = config.plugins || [];
-
- // Add our component path injector plugin
- plugins.push(componentPathInjectorPlugin(options));
-
- return {
- ...config,
- plugins,
- };
-};
+export const viteFinal = async (
+ config: UserConfig,
+ options: Options
+): Promise<UserConfig> => {
+ const existing = config.plugins;
+ const normalized: PluginOption[] = Array.isArray(existing)
+ ? [...existing]
+ : existing
+ ? [existing]
+ : [];
+
+ const inspector = componentPathInjectorPlugin(options);
+ // Ensure earliest execution within 'pre' group
+ return {
+ ...config,
+ plugins: [inspector, ...normalized],
+ };
+};📝 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.
| export const viteFinal = async ( | |
| config: import('vite').UserConfig, | |
| options: Options | |
| ): Promise<import('vite').UserConfig> => { | |
| const plugins = config.plugins || []; | |
| // Add our component path injector plugin | |
| plugins.push(componentPathInjectorPlugin(options)); | |
| return { | |
| ...config, | |
| plugins, | |
| }; | |
| }; | |
| import type { Options } from 'storybook/internal/types'; | |
| import type { PluginOption, UserConfig } from 'vite'; | |
| export const viteFinal = async ( | |
| config: UserConfig, | |
| options: Options | |
| ): Promise<UserConfig> => { | |
| const existing = config.plugins; | |
| const normalized: PluginOption[] = Array.isArray(existing) | |
| ? [...existing] | |
| : existing | |
| ? [existing] | |
| : []; | |
| const inspector = componentPathInjectorPlugin(options); | |
| // Ensure earliest execution within 'pre' group | |
| return { | |
| ...config, | |
| plugins: [inspector, ...normalized], | |
| }; | |
| }; |
🤖 Prompt for AI Agents
In code/addons/story-inspector/src/preset.ts around lines 5 to 18,
config.plugins may be undefined, a single PluginOption, or nested arrays;
pushing directly can throw at runtime. Normalize plugins into a flat array first
(treat undefined as [] and a non-array as [value], then flatten nested arrays),
append componentPathInjectorPlugin(options) to that new array, and return the
config with the normalized plugins array (do not mutate the original
config.plugins reference).
| export const parameters = { | ||
| [PARAM_KEY]: { | ||
| // Default to disabled - users can enable via toolbar | ||
| enabled: false, | ||
| }, | ||
| }; |
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.
Match parameters to the global shape.
useStoryInspector reads globals[PARAM_KEY] as a boolean. Setting the preview parameter to { enabled: false } populates globals.storyInspector with an object, so !!globals[PARAM_KEY] is always truthy. Initialize the parameter to false (no wrapper object) so the toggle reflects the toolbar state.
Apply this diff:
export const parameters = {
- [PARAM_KEY]: {
- // Default to disabled - users can enable via toolbar
- enabled: false,
- },
+ // Default to disabled - users can enable via the toolbar
+ [PARAM_KEY]: false,
};📝 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.
| export const parameters = { | |
| [PARAM_KEY]: { | |
| // Default to disabled - users can enable via toolbar | |
| enabled: false, | |
| }, | |
| }; | |
| export const parameters = { | |
| // Default to disabled - users can enable via the toolbar | |
| [PARAM_KEY]: false, | |
| }; |
🤖 Prompt for AI Agents
In code/addons/story-inspector/src/preview.ts around lines 21 to 26, the preview
parameter sets [PARAM_KEY] to an object ({ enabled: false }) which makes
globals[PARAM_KEY] an object and always truthy; change the parameter to a
boolean by initializing [PARAM_KEY]: false (you can keep the comment) so
globals.storyInspector is a boolean and the toolbar toggle reflects the actual
state.
| * This Vite plugin injects component file path metadata into JSX/TSX elements so they can be | ||
| * identified by the story inspector | ||
| */ | ||
| export function componentPathInjectorPlugin(options?: Options): any { |
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
Type the plugin and remove unused Options; expose a minimal options shape
Return type any hampers type-safety, and Options isn’t used. Type this as a Vite Plugin and allow an optional silent flag to control logging.
Apply:
-export function componentPathInjectorPlugin(options?: Options): any {
+export function componentPathInjectorPlugin(options: { silent?: boolean } = {}): import('vite').Plugin {Add the import (outside the shown range):
import type { Plugin } from 'vite';🤖 Prompt for AI Agents
In code/addons/story-inspector/src/utils/vite-plugin.ts around line 10, the
function currently returns any and accepts an unused Options type; replace that
with a properly typed Vite Plugin and a minimal options shape. Add the import
"import type { Plugin } from 'vite';" at top, remove the unused Options type,
define a small local interface (e.g. { silent?: boolean }), and change the
signature to export function componentPathInjectorPlugin(options?: { silent?:
boolean }): Plugin { ... } so logging can be controlled by options.silent and
the function returns a Plugin instead of any.
| "compilerOptions": { | ||
| "strict": false | ||
| }, |
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
Don’t disable TypeScript strict mode
Repo guideline: keep strict enabled. Re-enable strict here (or inherit from root).
"compilerOptions": {
- "strict": false
+ "strict": 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.
| "compilerOptions": { | |
| "strict": false | |
| }, | |
| "compilerOptions": { | |
| "strict": true | |
| }, |
🤖 Prompt for AI Agents
In code/addons/story-inspector/tsconfig.json lines 3-5, strict mode is disabled
("strict": false); change this to re-enable TypeScript strict checking by
setting "strict": true or remove the key so the project inherits the root
tsconfig strict setting, and ensure any resulting type errors are fixed or
narrow-scoped with proper type annotations to comply with the repo guideline.
| import { defineConfig } from 'vitest/config'; | ||
|
|
||
| export default defineConfig({ | ||
| test: { | ||
| globals: true, | ||
| environment: 'node', | ||
| }, | ||
| }); |
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
🧩 Analysis chain
Extend the workspace Vitest config instead of diverging per‑package settings
Keep this package aligned with code/vitest.workspace.ts and only override what’s necessary.
Apply:
-import { defineConfig } from 'vitest/config';
+import { defineConfig, mergeConfig } from 'vitest/config';
+import workspace from '../../vitest.workspace';
-export default defineConfig({
- test: {
- globals: true,
- environment: 'node',
- },
-});
+export default mergeConfig(
+ workspace,
+ defineConfig({
+ test: {
+ globals: true,
+ environment: 'node',
+ },
+ })
+);If any tests touch the DOM, prefer happy-dom/jsdom or per-test overrides. Quick check:
🏁 Script executed:
#!/bin/bash
# Find DOM usage in Story Inspector tests (adjust env if matches are found)
rg -n -C1 --type=ts --type=tsx '\b(document|window|HTMLElement|DOMParser)\b' code/addons/story-inspector/src/utils/__tests__ || trueLength of output: 27
🏁 Script executed:
#!/bin/bash
# Re-run DOM usage check without file-type filters
rg -n -C1 '\b(document|window|HTMLElement|DOMParser)\b' code/addons/story-inspector/src/utils/__tests__ || trueLength of output: 1375
🏁 Script executed:
#!/bin/bash
# Show workspace Vitest config to see default environment
sed -n '1,200p' code/vitest.workspace.tsLength of output: 1398
Extend workspace Vitest config and override only globals
-import { defineConfig } from 'vitest/config';
+import { defineConfig, mergeConfig } from 'vitest/config';
+import workspace from '../../vitest.workspace';
-export default defineConfig({
- test: {
- globals: true,
- environment: 'node',
- },
-});
+export default mergeConfig(
+ workspace,
+ defineConfig({
+ test: {
+ globals: true,
+ },
+ })
+);No need to override environment (defaults to 'node'). Tests mock the DOM manually; if you need a real DOM, switch to happy-dom/jsdom or use per-test overrides.
📝 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.
| import { defineConfig } from 'vitest/config'; | |
| export default defineConfig({ | |
| test: { | |
| globals: true, | |
| environment: 'node', | |
| }, | |
| }); | |
| import { defineConfig, mergeConfig } from 'vitest/config'; | |
| import workspace from '../../vitest.workspace'; | |
| export default mergeConfig( | |
| workspace, | |
| defineConfig({ | |
| test: { | |
| globals: true, | |
| }, | |
| }) | |
| ); |
🤖 Prompt for AI Agents
In code/addons/story-inspector/vitest.config.ts lines 1-8: remove the explicit
environment override and instead rely on the workspace Vitest config; keep only
the globals override. Concretely, delete the environment: 'node' entry so the
file only sets test.globals = true, or, if you need to explicitly inherit/extend
the workspace config, import/merge the workspace Vitest config and override only
the globals field; do not change environment here (use per-test overrides or
switch the workspace config to happy-dom/jsdom if a real DOM is required).
ea1fb64 to
968d4d5
Compare
43de3bb to
358a2d1
Compare
358a2d1 to
8f903c5
Compare
What I did
Checklist for Contributors
Testing
The changes in this PR are covered in the following automated tests:
Manual testing
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-32565-sha-8f903c5d. 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-32565-sha-8f903c5dyann/story-inspector8f903c5d1758893921)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 canary-release-pr.yml --field pr=32565Summary by CodeRabbit
New Features
Documentation
Tests
Chores