Skip to content

Conversation

@valentinpalkovic
Copy link
Contributor

@valentinpalkovic valentinpalkovic commented Nov 23, 2025

Closes #

What I did

  • Prevents install failures for projects using Vitest 3 by avoiding @vitest/browser-playwright (v4-only) unless Vitest
    4+ is detected.
  • Refactors AddonVitestService to accept packageManager via constructor, simplifying call sites and avoiding parameter
    threading.
  • Aligns create‑storybook and addon‑vitest postinstall to the new service API.

Checklist for Contributors

Testing

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

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

Manual testing

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

Documentation

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

Checklist for Maintainers

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

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

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

🦋 Canary release

This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

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

Summary by CodeRabbit

  • Refactor

    • Commands and services now receive a package manager via dependency injection; execution APIs simplified to rely on injected state and fewer call-time parameters. Public behavior unchanged.
  • Tests

    • Test suites updated to the new constructor and invocation patterns; mocks adjusted to the injected package manager approach.

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

@nx-cloud
Copy link

nx-cloud bot commented Nov 23, 2025

View your CI Pipeline Execution ↗ for commit 329b471

Command Status Duration Result
nx run-many -t build --parallel=3 ✅ Succeeded 44s View ↗

☁️ Nx Cloud last updated this comment at 2025-11-23 10:30:41 UTC

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 23, 2025

📝 Walkthrough

Walkthrough

Constructor-injects packageManager into multiple services and commands; methods that previously accepted packageManager parameters now use the injected instance. Call sites, wrapper helpers, and tests updated to construct commands/services with packageManager and to remove packageManager arguments from execute/validate/install calls.

Changes

Cohort / File(s) Summary
Addon Vitest Postinstall
code/addons/vitest/src/postinstall.ts
Instantiate AddonVitestService with a packageManager; postinstall flow updated to use the service instance constructed with that package manager.
Core AddonVitest Service & Tests
code/core/src/cli/AddonVitestService.ts, code/core/src/cli/AddonVitestService.test.ts
Add constructor accepting packageManager; remove packageManager params from collectDependencies, validatePackageVersions, installPlaywright; internal calls use this.packageManager; tests updated to inject mock package manager and drop explicit args.
Create-storybook — AddonConfiguration Command & Tests
code/lib/create-storybook/src/commands/AddonConfigurationCommand.ts, code/lib/create-storybook/src/commands/AddonConfigurationCommand.test.ts
Command constructor now accepts packageManager; execute() no longer takes packageManager; internal flows and postinstall calls use this.packageManager; tests updated to inject shared mock.
Create-storybook — DependencyInstallation Command & Tests
code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts, code/lib/create-storybook/src/commands/DependencyInstallationCommand.test.ts
DependencyInstallationCommand now constructed with packageManager; execute signature drops packageManager; addon dependency collection and install paths use this.packageManager; tests updated accordingly.
Create-storybook — UserPreferences Command & Tests
code/lib/create-storybook/src/commands/UserPreferencesCommand.ts, code/lib/create-storybook/src/commands/UserPreferencesCommand.test.ts
Constructor now accepts packageManager and injects services with it; execute() no longer takes packageManager; helpers/wrappers updated to pass object with packageManager; tests adapted.
Feature Compatibility Service & Tests
code/lib/create-storybook/src/services/FeatureCompatibilityService.ts, code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts
Constructor requires packageManager and constructs AddonVitestService(packageManager); validateTestFeatureCompatibility drops packageManager param and calls addon service with { framework, builder, projectRoot }; tests updated.
Initiation / User Preferences Integration
code/lib/create-storybook/src/initiate.ts
Call-site updated to pass a single object to executeUserPreferences including packageManager, options, framework, builder, and projectType; wrapper signature aligned.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Command
    participant Service
    participant PM as PackageManager

    rect rgb(240,240,255)
    Note over User,PM: Old flow (param-passing)
    User->>Command: new Command()
    User->>Command: execute(packageManager, opts)
    Command->>Service: new Service()
    Command->>Service: methodCall(packageManager, ...)
    Service->>PM: perform actions
    end

    rect rgb(235,255,235)
    Note over User,PM: New flow (constructor injection)
    User->>Command: new Command(packageManager)
    Command->>Command: this.packageManager = packageManager
    Command->>Service: new Service(packageManager)
    User->>Command: execute(opts)
    Command->>Service: methodCall(...)
    Service->>PM: perform actions (via this.packageManager)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Focus review on:
    • All instantiation sites and wrapper functions to ensure packageManager is provided and argument shapes match.
    • AddonVitestService internal logic: version detection, dependency collection, and Playwright install flow now using this.packageManager.
    • Tests that mock/inject packageManager to confirm mocks align with new constructor signatures.

Possibly related PRs

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 01e3d54 and 329b471.

📒 Files selected for processing (2)
  • code/core/src/cli/AddonVitestService.test.ts (22 hunks)
  • code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts (2)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/services/FeatureCompatibilityService.ts (1)
  • FeatureCompatibilityService (22-62)
code/core/src/cli/AddonVitestService.test.ts (1)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
⏰ 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). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (7)
code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts (2)

21-27: LGTM! Test setup properly updated for constructor injection.

The test correctly instantiates FeatureCompatibilityService with both mockPackageManager and mockAddonVitestService, aligning with the new constructor signature.


57-68: LGTM! Test calls correctly updated to match the new API.

The test properly calls validateTestFeatureCompatibility without a packageManager argument and verifies that the internal validateCompatibility is invoked with the correct parameters.

code/core/src/cli/AddonVitestService.test.ts (5)

33-34: LGTM! Test setup correctly implements constructor injection.

The service is properly instantiated with the mockPackageManager, and the getProjectRoot mock is appropriately configured for config file validation tests.


58-155: LGTM! All collectDependencies tests correctly updated.

All test calls properly invoke collectDependencies() without arguments, relying on the injected packageManager. The tests comprehensively cover different dependency scenarios including Vitest version detection and coverage reporters.


164-245: LGTM! Package version validation tests properly updated.

All validatePackageVersions() calls correctly invoke the method without arguments. The test suite comprehensively validates version compatibility checks for Vitest and MSW, including edge cases.


375-461: LGTM! Playwright installation tests correctly updated.

All installPlaywright() invocations properly use the no-packageManager signature, passing only the options parameter when needed. The test coverage includes error handling, user interaction, and various installation scenarios.


254-361: LGTM! Compatibility validation tests align with the new API.

All validateCompatibility() calls correctly pass options without a packageManager parameter. The tests comprehensively validate builder compatibility, framework support, version checks, and config file validation.


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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts (1)

19-27: FeatureCompatibilityService test is wired to the old API and wrong constructor types

This test still reflects the pre‑refactor API:

  • FeatureCompatibilityService is constructed with mockAddonVitestService, but the implementation now expects a JsPackageManager (and internally creates / accepts an AddonVitestService).
  • validateTestFeatureCompatibility is called with mockPackageManager as the first argument and asserts validateCompatibility receives a { packageManager, ... } object, while the implementation now only forwards { framework, builder, projectRoot }.

As written, this will no longer type‑check or correctly exercise the new behavior.

A minimal way to realign the test with the updated API is:

 describe('FeatureCompatibilityService', () => {
-  let service: FeatureCompatibilityService;
-  let mockAddonVitestService: AddonVitestService;
-
-  beforeEach(() => {
-    // @ts-expect-error accept old constructor in mock context
-    mockAddonVitestService = new AddonVitestService({} as any);
-    service = new FeatureCompatibilityService(mockAddonVitestService);
-  });
+  let service: FeatureCompatibilityService;
+  let mockAddonVitestService: AddonVitestService;
+  let mockPackageManager: JsPackageManager;
+  let mockValidateCompatibility: ReturnType<typeof vi.fn>;
@@
-  describe('validateTestFeatureCompatibility', () => {
-    let mockPackageManager: JsPackageManager;
-    let mockValidateCompatibility: ReturnType<typeof vi.fn>;
-
-    beforeEach(() => {
-      mockPackageManager = {
-        getInstalledVersion: vi.fn(),
-      } as Partial<JsPackageManager> as JsPackageManager;
-
-      // Get the mocked validateCompatibility method
-      mockValidateCompatibility = vi.mocked(mockAddonVitestService.validateCompatibility);
-    });
+  beforeEach(() => {
+    mockPackageManager = {
+      getInstalledVersion: vi.fn(),
+    } as Partial<JsPackageManager> as JsPackageManager;
+
+    // Local mock for AddonVitestService, injected into the service
+    mockAddonVitestService = {
+      validateCompatibility: vi.fn(),
+    } as unknown as AddonVitestService;
+
+    service = new FeatureCompatibilityService(mockPackageManager, mockAddonVitestService);
+    mockValidateCompatibility = vi.mocked(mockAddonVitestService.validateCompatibility);
+  });
+
+  describe('validateTestFeatureCompatibility', () => {
@@
-    it('should return compatible when all checks pass', async () => {
+    it('should return compatible when all checks pass', async () => {
       mockValidateCompatibility.mockResolvedValue({ compatible: true });
 
       const result = await service.validateTestFeatureCompatibility(
-        mockPackageManager,
         SupportedFramework.REACT_VITE,
         SupportedBuilder.VITE,
         '/test'
       );
@@
-      expect(mockValidateCompatibility).toHaveBeenCalledWith({
-        packageManager: mockPackageManager,
-        framework: 'react-vite',
-        builder: SupportedBuilder.VITE,
-        projectRoot: '/test',
-      });
+      expect(mockValidateCompatibility).toHaveBeenCalledWith({
+        framework: 'react-vite',
+        builder: SupportedBuilder.VITE,
+        projectRoot: '/test',
+      });
@@
-      const result = await service.validateTestFeatureCompatibility(
-        mockPackageManager,
-        SupportedFramework.REACT_VITE,
-        SupportedBuilder.VITE,
-        '/test'
-      );
+      const result = await service.validateTestFeatureCompatibility(
+        SupportedFramework.REACT_VITE,
+        SupportedBuilder.VITE,
+        '/test'
+      );

This makes the test match:

  • The new constructor signature (new FeatureCompatibilityService(packageManager, addonVitestService?)).
  • The updated validateTestFeatureCompatibility(framework, builder, directory) signature.
  • The new AddonVitestService.validateCompatibility call shape.

Also applies to: 45-56, 58-75, 77-93

code/core/src/cli/AddonVitestService.test.ts (2)

21-43: Fix initialization order in beforeEach: service is created before mockPackageManager is assigned

In beforeEach, service = new AddonVitestService(mockPackageManager); runs while mockPackageManager is still undefined (first test) or before it’s reassigned (subsequent tests). As a result, this.packageManager inside the service is either undefined or points at a stale instance, and any method that calls this.packageManager.* will fail or use the wrong mock.

Reorder setup so the mock is created first and then passed into the service:

-  beforeEach(() => {
-    vi.clearAllMocks();
-    service = new AddonVitestService(mockPackageManager);
-    vi.mocked(getProjectRoot).mockReturnValue('/test/project');
-
-    mockPackageManager = {
-      getAllDependencies: vi.fn(),
-      getInstalledVersion: vi.fn(),
-      runPackageCommand: vi.fn(),
-    } as Partial<JsPackageManager> as JsPackageManager;
+  beforeEach(() => {
+    vi.clearAllMocks();
+
+    mockPackageManager = {
+      getAllDependencies: vi.fn(),
+      getInstalledVersion: vi.fn(),
+      runPackageCommand: vi.fn(),
+    } as Partial<JsPackageManager> as JsPackageManager;
+
+    service = new AddonVitestService(mockPackageManager);
+    vi.mocked(getProjectRoot).mockReturnValue('/test/project');

(Keep the logger/prompt mocks as they are after this block.)


45-246: Align tests with constructor-injected AddonVitestService API (drop mockPackageManager arguments)

Now that AddonVitestService takes JsPackageManager via its constructor and methods use this.packageManager internally, update all instance method calls to remove the mockPackageManager parameter:

  • collectDependencies: lines 124, 136, 148
  • validatePackageVersions: lines 208, 220, 230, 240
  • installPlaywright: lines 384, 412, 427, 438, 447, 455, 466
-      const deps = await service.collectDependencies(mockPackageManager);
+      const deps = await service.collectDependencies();

-      const result = await service.validatePackageVersions(mockPackageManager);
+      const result = await service.validatePackageVersions();

-      const { errors } = await service.installPlaywright(mockPackageManager);
+      const { errors } = await service.installPlaywright();
🧹 Nitpick comments (4)
code/addons/vitest/src/postinstall.ts (1)

61-61: AddonVitestService DI and usage look correct; minor duplication of Vitest version logic

Constructing a single AddonVitestService(packageManager) and then using validateCompatibility(), collectDependencies(), and installPlaywright({ yes }) matches the new API and keeps package-manager concerns centralized. The only minor nit is that Vitest version detection now lives both here (isVitest3_2To4 / isVitest4OrNewer) and inside AddonVitestService.collectDependencies(), so if version rules change in future it might be worth pulling that into one shared helper/service to avoid divergence.

Also applies to: 99-99, 141-143

code/lib/create-storybook/src/services/FeatureCompatibilityService.ts (1)

23-26: Constructor DI for AddonVitestService is sound; JSDoc still mentions removed packageManager param

Injecting JsPackageManager via the FeatureCompatibilityService constructor and constructing AddonVitestService with it is a clean, testable pattern; validateTestFeatureCompatibility correctly delegates to this.addonVitestService.validateCompatibility({ framework, builder, projectRoot: directory }).

The JSDoc above validateTestFeatureCompatibility still lists @param packageManager, but the method signature no longer takes that argument. It would be good to drop or update that tag to avoid confusion.

Also applies to: 45-49

code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts (1)

24-27: Constructor‑injected packageManager usage and Vitest dependency collection look correct

Injecting JsPackageManager into DependencyInstallationCommand and using this.packageManager for addDependencies/installDependencies lines up with the rest of the refactor, and collectAddonDependencies correctly delegates Vitest devDeps to new AddonVitestService(this.packageManager).collectDependencies().

If you want to tighten intent slightly, you could mark the constructor fields as readonly:

-  constructor(
-    private dependencyCollector: DependencyCollector,
-    private packageManager: JsPackageManager
-  ) {}
+  constructor(
+    private readonly dependencyCollector: DependencyCollector,
+    private readonly packageManager: JsPackageManager
+  ) {}

but functionally this looks good.

Also applies to: 33-34, 49-52, 60-63, 71-71, 81-90, 93-103

code/lib/create-storybook/src/commands/AddonConfigurationCommand.ts (1)

36-39: Addon configuration DI and Playwright installation integration look consistent

Passing JsPackageManager into AddonConfigurationCommand and constructing a single AddonVitestService(packageManager) aligns with the new API, and configureAddons correctly forwards this.packageManager.type into postinstallAddon while keeping skipInstall/skipDependencyManagement true. The follow‑up addonVitestService.installPlaywright({ yes: options.yes }) hook is a clear place to centralize Playwright binary installation.

If you later want more visibility into Playwright failures, you could capture and act on the { errors } returned from installPlaywright, but the current behavior matches the previous pattern of ignoring that detail here.

Also applies to: 60-67, 106-107, 123-131, 162-167

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d5bb853 and 44bc707.

📒 Files selected for processing (11)
  • code/addons/vitest/src/postinstall.ts (3 hunks)
  • code/core/src/cli/AddonVitestService.test.ts (9 hunks)
  • code/core/src/cli/AddonVitestService.ts (9 hunks)
  • code/lib/create-storybook/src/commands/AddonConfigurationCommand.test.ts (2 hunks)
  • code/lib/create-storybook/src/commands/AddonConfigurationCommand.ts (5 hunks)
  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.test.ts (1 hunks)
  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts (6 hunks)
  • code/lib/create-storybook/src/commands/UserPreferencesCommand.test.ts (8 hunks)
  • code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (3 hunks)
  • code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts (1 hunks)
  • code/lib/create-storybook/src/services/FeatureCompatibilityService.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-29T13:20:23.346Z
Learnt from: mrginglymus
Repo: storybookjs/storybook PR: 32556
File: code/core/package.json:309-313
Timestamp: 2025-09-29T13:20:23.346Z
Learning: The `fast-printf` dependency in Storybook's core package is bundled into the final distribution during the build process, so it should remain in devDependencies rather than being moved to dependencies, following the same pattern as other bundled dependencies like `open`.

Applied to files:

  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.test.ts
  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.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/lib/create-storybook/src/commands/DependencyInstallationCommand.test.ts
  • code/core/src/cli/AddonVitestService.ts
  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts
🧬 Code graph analysis (10)
code/lib/create-storybook/src/commands/DependencyInstallationCommand.test.ts (2)
code/lib/create-storybook/src/dependency-collector.ts (1)
  • DependencyCollector (19-185)
code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts (1)
  • DependencyInstallationCommand (23-91)
code/lib/create-storybook/src/commands/UserPreferencesCommand.test.ts (1)
code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (1)
  • UserPreferencesCommand (45-219)
code/lib/create-storybook/src/services/FeatureCompatibilityService.ts (1)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/core/src/cli/AddonVitestService.test.ts (1)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/commands/AddonConfigurationCommand.test.ts (2)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/commands/AddonConfigurationCommand.ts (1)
  • AddonConfigurationCommand (35-160)
code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts (2)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/dependency-collector.ts (1)
  • DependencyCollector (19-185)
code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts (1)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/addons/vitest/src/postinstall.ts (1)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (2)
code/lib/create-storybook/src/services/FeatureCompatibilityService.ts (1)
  • FeatureCompatibilityService (22-62)
code/lib/create-storybook/src/generators/types.ts (1)
  • CommandOptions (118-137)
code/lib/create-storybook/src/commands/AddonConfigurationCommand.ts (2)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/generators/types.ts (1)
  • CommandOptions (118-137)
⏰ 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). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (8)
code/lib/create-storybook/src/commands/UserPreferencesCommand.test.ts (1)

35-45: Tests correctly follow constructor‑injected packageManager and new execute API

UserPreferencesCommand is now instantiated with mockPackageManager, and all calls to execute use a single options argument. This matches the refactored command signature and keeps the tests focused on behavior rather than wiring.

Also applies to: 87-203

code/lib/create-storybook/src/commands/AddonConfigurationCommand.test.ts (1)

20-27: AddonConfigurationCommand tests correctly adopt constructor‑injected packageManager

Instantiating AddonConfigurationCommand with mockPackageManager and asserting postinstallAddon receives packageManager: 'npm' matches the refactored command that reads this.packageManager.type. The AddonVitestService mock keeps installPlaywright isolated from these tests.

Also applies to: 36-50

code/lib/create-storybook/src/commands/DependencyInstallationCommand.test.ts (1)

11-20: DependencyInstallationCommand tests now match constructor‑injected packageManager

Using a shared mockPackageManager and constructing DependencyInstallationCommand with (dependencyCollector, mockPackageManager) aligns with the new command API. The existing expectations around addDependencies / installDependencies behavior remain valid.

code/core/src/cli/AddonVitestService.ts (5)

39-39: LGTM! Dependency injection simplifies the API.

The constructor-based injection of packageManager removes parameter threading across all methods, improving both testability and the public API surface.


82-113: LGTM! Conditional package selection prevents v3 install failures.

The conditional selection between @vitest/browser-playwright (v4+) and @vitest/browser (v3) correctly addresses the compatibility issue. Applying the version specifier to all vitest-related packages ensures ecosystem consistency.


127-175: LGTM! Method signature aligned with constructor injection.

The simplified signature removes the packageManager parameter while maintaining all existing functionality through this.packageManager.


190-252: LGTM! Validation methods correctly use injected dependency.

Both validateCompatibility and validatePackageVersions correctly reference this.packageManager and maintain their original validation logic.


65-79: Verify pre-release version handling and confirm edge case severity.

The version detection logic has two edge cases that warrant verification:

  1. Pre-release versions: @vitest/browser has versions ranging from v2.x through v3.x (latest 3.1.3), and in Vitest v4, @vitest/browser is now included in every provider package automatically. The semver library's satisfies() function returns false for pre-release versions when using range comparisons like >=4.0.0—meaning a project with vitest: "4.0.0-beta.0" would be classified as v3 and install @vitest/browser instead of @vitest/browser-playwright.

  2. Unparseable versions: If a version string cannot be parsed by validRange/minVersion or coerce, the code defaults to isVitest4OrNewer = true. While this is a reasonable defensive choice for the common case (no vitest installed → install latest), it could fail if a project has a malformed version string but is actually on v3.

In Vitest v4, you need to install a separate package: @vitest/browser-playwright, @vitest/browser-webdriverio, or @vitest/browser-preview, and the npm data confirms these packages exist only for v4. Confirm whether pre-release versions or unparseable version strings are expected in your environment, and consider adding an explicit fallback or logging when version detection fails to handle these cases defensively.

@valentinpalkovic valentinpalkovic force-pushed the valentin/cleanup-and-vitest-4-fix branch from 44bc707 to dacacab Compare November 23, 2025 09:43
@valentinpalkovic valentinpalkovic changed the title Fix Vitest v3 installs and refactor AddonVitestService; align create‑storybook usage CLI: Fix Vitest v3 installs and refactor AddonVitestService; align create‑storybook usage Nov 23, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
code/lib/create-storybook/src/commands/DependencyInstallationCommand.test.ts (1)

93-101: Fix assertion on getAllPackages() to actually check for Vitest absence

dependencyCollector.getAllPackages() returns an object { dependencies, devDependencies }, but toContain('vitest') expects an array or string, so this assertion never meaningfully inspects the underlying lists.

Consider asserting on the flattened dependency arrays instead, for example:

const { dependencies, devDependencies } = dependencyCollector.getAllPackages();
expect([...dependencies, ...devDependencies]).not.toContain(
  expect.stringContaining('vitest')
);

This will correctly guarantee that no Vitest packages were added when Feature.TEST is not selected.

Also applies to: 103-110

code/core/src/cli/AddonVitestService.test.ts (2)

117-156: Align tests with constructor-injected API and correct the coverage/istanbul scenario

Now that AddonVitestService holds the JsPackageManager via its constructor:

  • collectDependencies and validatePackageVersions no longer need a package manager parameter, yet some tests still call them with mockPackageManager (e.g., Lines 124, 136, 148, 208, 220, 230, 240). Those extra arguments are ignored, but they obscure the fact that the injected this.packageManager is what matters.
  • Similarly, installPlaywright takes an options object ({ yes?: boolean }) but is still being invoked as service.installPlaywright(mockPackageManager). This works only because the extra properties are ignored.

For clarity and to better reflect the public API, consider:

  • Calling service.collectDependencies() and service.validatePackageVersions() without arguments.
  • Updating the Playwright tests to call service.installPlaywright() or service.installPlaywright({ yes: true }) and keep all assertions around prompt and runPackageCommand as they are.

Additionally, in it('skips coverage if istanbul', ...), the mocked getInstalledVersion sequence:

vi.mocked(mockPackageManager.getInstalledVersion)
  .mockResolvedValueOnce(null) // currently used for vitest
  .mockResolvedValueOnce('3.0.0') // currently used for @vitest/coverage-v8
  .mockResolvedValueOnce(null); // currently used for @vitest/coverage-istanbul

actually simulates "@vitest/coverage-v8 installed" again rather than "istanbul-only". To truly exercise the "istanbul installed, v8 absent" path with the current implementation order (vitest@vitest/coverage-v8@vitest/coverage-istanbul), you likely want:

vi.mocked(mockPackageManager.getInstalledVersion)
  .mockResolvedValueOnce(null)      // vitest version
  .mockResolvedValueOnce(null)      // @vitest/coverage-v8
  .mockResolvedValueOnce('3.0.0');  // @vitest/coverage-istanbul

This will give you distinct coverage for both v8-installed and istanbul-installed branches.

Also applies to: 181-245, 373-471


21-35: Fix beforeEach ordering: service is constructed with an undefined/stale packageManager

In beforeEach, service is created before mockPackageManager is initialized, and mockPackageManager is then reassigned:

beforeEach(() => {
  vi.clearAllMocks();
  service = new AddonVitestService(mockPackageManager); // mockPackageManager is undefined on first run
  vi.mocked(getProjectRoot).mockReturnValue('/test/project');

  mockPackageManager = {
    getAllDependencies: vi.fn(),
    getInstalledVersion: vi.fn(),
    runPackageCommand: vi.fn(),
  } as Partial<JsPackageManager> as JsPackageManager;
});

This means:

  • The first test constructs AddonVitestService with undefined as packageManager, causing runtime failures when methods hit this.packageManager.*.
  • Subsequent tests construct service with the previous mockPackageManager instance, while stubbing methods on the newly assigned one, so mocks don't line up with what service actually uses.

Reorder to initialize the mock before constructing the service:

  beforeEach(() => {
    vi.clearAllMocks();
+
+   mockPackageManager = {
+     getAllDependencies: vi.fn(),
+     getInstalledVersion: vi.fn(),
+     runPackageCommand: vi.fn(),
+   } as Partial<JsPackageManager> as JsPackageManager;
+
    service = new AddonVitestService(mockPackageManager);
    vi.mocked(getProjectRoot).mockReturnValue('/test/project');
-
-   mockPackageManager = {
-     getAllDependencies: vi.fn(),
-     getInstalledVersion: vi.fn(),
-     runPackageCommand: vi.fn(),
-   } as Partial<JsPackageManager> as JsPackageManager;
  });
♻️ Duplicate comments (1)
code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (1)

46-51: Constructor parameter default uses this before instance initialization.

In constructor parameter initializers, this properties are not yet assigned when default values are evaluated. Using this.packageManager in the default value for featureService will result in undefined being passed to FeatureCompatibilityService.

Apply this diff to reference the raw parameter instead:

 export class UserPreferencesCommand {
   constructor(
     private commandOptions: CommandOptions,
     private packageManager: JsPackageManager,
-    private featureService = new FeatureCompatibilityService(this.packageManager),
+    private featureService = new FeatureCompatibilityService(packageManager),
     private telemetryService = new TelemetryService(commandOptions.disableTelemetry)
   ) {}
🧹 Nitpick comments (1)
code/lib/create-storybook/src/commands/DependencyInstallationCommand.test.ts (1)

11-22: DependencyInstallationCommand.test.ts is missing AddonVitestService mock used by sibling tests

Verification confirms the concern: other tests in the same directory (notably AddonConfigurationCommand.test.ts and UserPreferencesCommand.test.ts) properly mock AddonVitestService using vi.fn().mockImplementation(), but DependencyInstallationCommand.test.ts does not.

When execute() calls collectAddonDependencies() (which instantiates AddonVitestService with the injected mockPackageManager at line 84 of the implementation), the service will attempt to call getAllDependencies() and getInstalledVersion() on the mock—methods that do not exist. Although errors are caught and logged internally, this creates unnecessary noise and inconsistency with the established test pattern.

Consider either extending mockPackageManager to include no-op stubs for those methods, or add a vi.mock('storybook/internal/cli') block with an implementation matching the pattern in AddonConfigurationCommand.test.ts (lines 41–47).

Also applies to: 25-38, 40-48

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 44bc707 and dacacab.

📒 Files selected for processing (12)
  • code/addons/vitest/src/postinstall.ts (3 hunks)
  • code/core/src/cli/AddonVitestService.test.ts (9 hunks)
  • code/core/src/cli/AddonVitestService.ts (9 hunks)
  • code/lib/create-storybook/src/commands/AddonConfigurationCommand.test.ts (2 hunks)
  • code/lib/create-storybook/src/commands/AddonConfigurationCommand.ts (5 hunks)
  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.test.ts (1 hunks)
  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts (6 hunks)
  • code/lib/create-storybook/src/commands/UserPreferencesCommand.test.ts (8 hunks)
  • code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (3 hunks)
  • code/lib/create-storybook/src/initiate.ts (1 hunks)
  • code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts (1 hunks)
  • code/lib/create-storybook/src/services/FeatureCompatibilityService.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • code/lib/create-storybook/src/commands/UserPreferencesCommand.test.ts
  • code/lib/create-storybook/src/services/FeatureCompatibilityService.ts
  • code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts
  • code/addons/vitest/src/postinstall.ts
🧰 Additional context used
🧠 Learnings (3)
📚 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/cli/AddonVitestService.ts
  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts
  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.test.ts
📚 Learning: 2025-09-29T13:20:23.346Z
Learnt from: mrginglymus
Repo: storybookjs/storybook PR: 32556
File: code/core/package.json:309-313
Timestamp: 2025-09-29T13:20:23.346Z
Learning: The `fast-printf` dependency in Storybook's core package is bundled into the final distribution during the build process, so it should remain in devDependencies rather than being moved to dependencies, following the same pattern as other bundled dependencies like `open`.

Applied to files:

  • code/core/src/cli/AddonVitestService.ts
  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts
  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.test.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/lib/create-storybook/src/commands/UserPreferencesCommand.ts
🧬 Code graph analysis (7)
code/lib/create-storybook/src/initiate.ts (1)
code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (1)
  • executeUserPreferences (221-227)
code/lib/create-storybook/src/commands/AddonConfigurationCommand.ts (3)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/generators/types.ts (1)
  • CommandOptions (118-137)
code/lib/create-storybook/src/commands/index.ts (1)
  • executeAddonConfiguration (24-24)
code/core/src/cli/AddonVitestService.test.ts (1)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts (2)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/dependency-collector.ts (1)
  • DependencyCollector (19-185)
code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (3)
code/lib/create-storybook/src/services/FeatureCompatibilityService.ts (1)
  • FeatureCompatibilityService (22-62)
code/lib/create-storybook/src/services/TelemetryService.ts (1)
  • TelemetryService (10-105)
code/lib/create-storybook/src/generators/types.ts (1)
  • CommandOptions (118-137)
code/lib/create-storybook/src/commands/AddonConfigurationCommand.test.ts (2)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/commands/AddonConfigurationCommand.ts (1)
  • AddonConfigurationCommand (35-160)
code/lib/create-storybook/src/commands/DependencyInstallationCommand.test.ts (2)
code/lib/create-storybook/src/dependency-collector.ts (1)
  • DependencyCollector (19-185)
code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts (1)
  • DependencyInstallationCommand (23-91)
⏰ 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). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (10)
code/lib/create-storybook/src/commands/AddonConfigurationCommand.test.ts (1)

20-27: AddonConfigurationCommand DI and mocks are aligned with the new API

Injecting mockPackageManager into AddonConfigurationCommand and asserting that postinstallAddon receives packageManager: 'npm' matches the updated constructor and configureAddons implementation. The AddonVitestService mock and postinstallAddon spy setup look consistent and should keep these tests decoupled from real CLI behavior.

Also applies to: 36-49, 129-164

code/lib/create-storybook/src/initiate.ts (1)

60-67: Updated executeUserPreferences call correctly matches the new object-based API

Passing a single options object including packageManager, options, framework, builder, and projectType is consistent with the refactored executeUserPreferences helper. This keeps doInitiate in sync with the new constructor/execute signature of UserPreferencesCommand and ensures project type is available for preference handling.

code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts (1)

23-33: DependencyInstallationCommand DI refactor and Vitest integration look sound

Injecting JsPackageManager via the constructor and using this.packageManager throughout execute simplifies the call sites and cleanly supports the new AddonVitestService API. The collectAddonDependencies helper correctly:

  • Checks selectedFeatures for Feature.TEST,
  • Uses new AddonVitestService(this.packageManager).collectDependencies() to derive devDeps, and
  • Safely degrades by logging and continuing on errors.

The executeDependencyInstallation wrapper now passes both dependencyCollector and packageManager into the command and forwards only the relevant skipInstall / selectedFeatures fields into execute, which keeps responsibilities well separated.

Also applies to: 46-52, 55-64, 68-77, 80-90, 93-102

code/lib/create-storybook/src/commands/AddonConfigurationCommand.ts (3)

36-39: LGTM! Constructor injection pattern applied correctly.

The constructor now accepts packageManager and properly initializes addonVitestService with it, centralizing dependency management within the service.


61-66: LGTM! Method calls updated to use injected dependencies.

Both configureAddons and addonVitestService.installPlaywright calls correctly rely on the injected packageManager instance rather than passing it as a parameter.


162-166: LGTM! Wrapper function correctly implements new pattern.

The executeAddonConfiguration wrapper properly extracts packageManager, instantiates the command with it, and forwards the remaining options to execute.

code/core/src/cli/AddonVitestService.ts (3)

65-79: LGTM! Version detection prevents v3 incompatibility issues.

The logic correctly determines the Vitest version by checking both installed and declared dependencies, then uses semver helpers (validRange, minVersion, coerce, satisfies) to conditionally install @vitest/browser-playwright (v4+) or @vitest/browser (v3).

The default of isVitest4OrNewer = true is pragmatic: if vitest is uninstalled/undeclared, the latest version (likely v4+) will be installed anyway. If parsing fails on a declared version, assuming newer is safer than blocking installation.


82-86: LGTM! Conditional package selection addresses the PR objective.

This change directly solves the install failure for Vitest v3 projects by selecting the correct browser package based on the detected version.


39-39: LGTM! Constructor injection consistently applied.

All method signatures correctly updated to rely on this.packageManager instead of accepting it as a parameter, simplifying the API surface.

Also applies to: 61-61, 127-127, 228-228

code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (1)

221-226: LGTM! Wrapper function correctly implements constructor injection.

The executeUserPreferences wrapper properly extracts packageManager and options, instantiates the command with them, and forwards the remaining options to execute.

…eManager; align create-storybook and postinstall call sites; fix Vitest v3 projects to avoid adding @vitest/browser-playwright by default
@valentinpalkovic valentinpalkovic force-pushed the valentin/cleanup-and-vitest-4-fix branch from dacacab to 01e3d54 Compare November 23, 2025 09:56
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts (1)

24-25: Consider using a proper mock packageManager.

The @ts-expect-error with {} as any bypasses type checking. While this works because the vi.mock provides method implementations, a proper mock packageManager would be more maintainable:

 beforeEach(() => {
-  // @ts-expect-error accept old constructor in mock context
-  mockAddonVitestService = new AddonVitestService({} as any);
+  const mockPackageManager = {
+    getAllDependencies: vi.fn().mockReturnValue({}),
+    getInstalledVersion: vi.fn().mockResolvedValue(undefined),
+  } as Partial<JsPackageManager> as JsPackageManager;
+  mockAddonVitestService = new AddonVitestService(mockPackageManager);
   service = new FeatureCompatibilityService(mockAddonVitestService);
 });

This makes the test more explicit and avoids potential issues if AddonVitestService's constructor logic changes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dacacab and 01e3d54.

📒 Files selected for processing (12)
  • code/addons/vitest/src/postinstall.ts (3 hunks)
  • code/core/src/cli/AddonVitestService.test.ts (9 hunks)
  • code/core/src/cli/AddonVitestService.ts (9 hunks)
  • code/lib/create-storybook/src/commands/AddonConfigurationCommand.test.ts (2 hunks)
  • code/lib/create-storybook/src/commands/AddonConfigurationCommand.ts (5 hunks)
  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.test.ts (1 hunks)
  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts (6 hunks)
  • code/lib/create-storybook/src/commands/UserPreferencesCommand.test.ts (8 hunks)
  • code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (3 hunks)
  • code/lib/create-storybook/src/initiate.ts (1 hunks)
  • code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts (1 hunks)
  • code/lib/create-storybook/src/services/FeatureCompatibilityService.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.test.ts
  • code/lib/create-storybook/src/initiate.ts
  • code/core/src/cli/AddonVitestService.test.ts
  • code/lib/create-storybook/src/commands/UserPreferencesCommand.test.ts
🧰 Additional context used
🧠 Learnings (4)
📚 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/lib/create-storybook/src/commands/DependencyInstallationCommand.ts
  • code/core/src/cli/AddonVitestService.ts
📚 Learning: 2025-09-29T13:20:23.346Z
Learnt from: mrginglymus
Repo: storybookjs/storybook PR: 32556
File: code/core/package.json:309-313
Timestamp: 2025-09-29T13:20:23.346Z
Learning: The `fast-printf` dependency in Storybook's core package is bundled into the final distribution during the build process, so it should remain in devDependencies rather than being moved to dependencies, following the same pattern as other bundled dependencies like `open`.

Applied to files:

  • code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts
  • code/core/src/cli/AddonVitestService.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/lib/create-storybook/src/services/FeatureCompatibilityService.test.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/lib/create-storybook/src/commands/UserPreferencesCommand.ts
🧬 Code graph analysis (7)
code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts (3)
code/lib/create-storybook/src/dependency-collector.ts (1)
  • DependencyCollector (19-185)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/commands/index.ts (1)
  • executeDependencyInstallation (26-26)
code/lib/create-storybook/src/services/FeatureCompatibilityService.ts (1)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts (1)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/commands/AddonConfigurationCommand.test.ts (2)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/commands/AddonConfigurationCommand.ts (1)
  • AddonConfigurationCommand (35-160)
code/lib/create-storybook/src/commands/AddonConfigurationCommand.ts (2)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
code/lib/create-storybook/src/generators/types.ts (1)
  • CommandOptions (118-137)
code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (3)
code/lib/create-storybook/src/generators/types.ts (1)
  • CommandOptions (118-137)
code/lib/create-storybook/src/services/FeatureCompatibilityService.ts (1)
  • FeatureCompatibilityService (22-62)
code/lib/create-storybook/src/services/TelemetryService.ts (1)
  • TelemetryService (10-105)
code/addons/vitest/src/postinstall.ts (1)
code/core/src/cli/AddonVitestService.ts (1)
  • AddonVitestService (38-384)
⏰ 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). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (18)
code/core/src/cli/AddonVitestService.ts (4)

39-39: LGTM: Constructor properly injects packageManager.

The constructor now accepts packageManager as a required dependency, enabling all methods to use this.packageManager internally. This eliminates parameter threading.


85-86: Correct browser package selection based on Vitest version.

The conditional logic correctly installs:

  • @vitest/browser-playwright for Vitest v4+
  • @vitest/browser for Vitest v3.x

This addresses the PR's main goal of preventing v3 install failures.


96-99: LGTM: Refactored methods use injected packageManager.

All methods (collectDependencies, installPlaywright, validatePackageVersions) now use this.packageManager instead of accepting it as a parameter. Signatures simplified accordingly.

Also applies to: 127-149


61-79: The version detection logic is correct and well-designed.

After examining the implementation, the dual-detection mechanism is intentional and robust:

  1. getInstalledVersion() (JsPackageManager.ts:615-649) uses findInstallations() which delegates to package manager CLIs (npm ls, yarn list, pnpm list), covering installed packages in node_modules or pnp zips.

  2. getAllDependencies() (JsPackageManager.ts:221-232) explicitly supports monorepos by iterating through packageJsonPaths and merging all dependencies, devDependencies, and peerDependencies from every package.json file.

  3. Tests confirm the design (AddonVitestService.test.ts:58) verify expected behavior when getInstalledVersion returns null, and this pattern is consistently used elsewhere (e.g., helpers.ts).

For both checks to fail on an existing Vitest v3 installation would require a severely corrupted installation or an unusual monorepo misconfiguration. The default isVitest4OrNewer = true is appropriate for fresh setups and acts as a safe fallback.

code/addons/vitest/src/postinstall.ts (2)

61-61: LGTM: AddonVitestService instantiated with packageManager.

Correctly constructs the service with the required packageManager dependency.


99-99: LGTM: Method calls updated to new signatures.

collectDependencies() and installPlaywright({ yes }) called without packageManager parameter, matching the refactored API.

Also applies to: 141-143

code/lib/create-storybook/src/commands/AddonConfigurationCommand.test.ts (1)

22-26: LGTM: Test setup updated for constructor injection.

The shared mockPackageManager and command construction align with the new dependency injection pattern.

Also applies to: 49-49

code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts (3)

24-28: LGTM: Constructor properly initializes dependencies.

The command now accepts packageManager and uses it to initialize addonVitestService, following the same pattern as other commands in this refactor.


85-85: LGTM: Dependency collection updated to new API.

collectDependencies() correctly called without the packageManager parameter.


94-101: LGTM: Wrapper function updated for dependency injection.

The executeDependencyInstallation wrapper now accepts and passes packageManager to the constructor, maintaining a clean separation between construction and execution.

code/lib/create-storybook/src/services/FeatureCompatibilityService.ts (2)

23-26: LGTM: Service initialized with packageManager.

The constructor properly accepts packageManager and uses it to initialize addonVitestService, consistent with the refactoring pattern.


45-54: LGTM: Method signature simplified.

validateTestFeatureCompatibility no longer needs packageManager as a parameter since it's available via this.addonVitestService.

code/lib/create-storybook/src/commands/AddonConfigurationCommand.ts (3)

36-39: LGTM: Constructor dependency injection implemented.

The command now receives packageManager as a constructor parameter and uses it to initialize addonVitestService.


106-106: LGTM: Internal methods use injected packageManager.

configureAddons no longer needs packageManager as a parameter. Line 124 correctly uses this.packageManager.type.

Also applies to: 124-124


162-167: LGTM: Wrapper function follows injection pattern.

executeAddonConfiguration extracts packageManager from params and constructs the command with it, then passes remaining options to execute().

code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (3)

46-51: LGTM: Constructor properly initializes services with packageManager.

The constructor correctly uses the packageManager parameter (not this.packageManager) in the default initializer for featureService. This addresses the previous review concern about accessing this before instance creation.


54-54: LGTM: Method signature simplified.

execute() no longer needs packageManager as a parameter since it's available via the injected featureService.


221-227: LGTM: Wrapper follows consistent injection pattern.

executeUserPreferences extracts packageManager and options, constructs the command with both, then executes with remaining parameters.

@valentinpalkovic valentinpalkovic merged commit 29fb84b into next Nov 24, 2025
66 of 67 checks passed
@valentinpalkovic valentinpalkovic deleted the valentin/cleanup-and-vitest-4-fix branch November 24, 2025 10:43
@github-actions github-actions bot mentioned this pull request Nov 24, 2025
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants