@@ -632,10 +632,9 @@ describe('rewritePackageJson', () => {
632632 expect ( pkg . devDependencies ) . not . toHaveProperty ( '@vitest/browser' ) ;
633633 } ) ;
634634
635- it ( 'pins the provider framework peer to a lockstep sibling instead of * (npmx.dev #27)' , ( ) => {
636- // `playwright` and `@playwright/test` release in lockstep, so a newly-added
637- // `playwright` peer should reuse the pinned @playwright/test version rather
638- // than a non-deterministic `*`.
635+ it ( 'does not add playwright when @playwright/test already provides it' , ( ) => {
636+ // `@playwright/test` has a dependency on `playwright`,
637+ // so adding a second direct dependency is redundant.
639638 const pkg = {
640639 devDependencies : {
641640 '@vitest/browser-playwright' : '^4.0.0' ,
@@ -644,7 +643,7 @@ describe('rewritePackageJson', () => {
644643 } ,
645644 } ;
646645 rewritePackageJson ( pkg , PackageManager . pnpm ) ;
647- expect ( pkg . devDependencies ) . toHaveProperty ( 'playwright' , '1.60.0 ') ;
646+ expect ( pkg . devDependencies ) . not . toHaveProperty ( 'playwright' ) ;
648647 } ) ;
649648
650649 it ( 'injects a direct vite devDependency for an npm project that uses an opt-in browser provider' , async ( ) => {
@@ -3409,6 +3408,56 @@ describe('ensureVitePlusBootstrap', () => {
34093408 expect ( detectVitePlusBootstrapPending ( tmpDir , PackageManager . pnpm ) ) . toBe ( false ) ;
34103409 } ) ;
34113410
3411+ it ( 'does not add playwright on upgrade when @playwright/test already provides it' , ( ) => {
3412+ fs . writeFileSync (
3413+ path . join ( tmpDir , 'package.json' ) ,
3414+ JSON . stringify ( {
3415+ name : 'browser-app' ,
3416+ devDependencies : {
3417+ '@playwright/test' : '1.60.0' ,
3418+ 'vite-plus' : 'catalog:' ,
3419+ } ,
3420+ devEngines : {
3421+ packageManager : { name : 'pnpm' , version : '10.33.0' , onFail : 'download' } ,
3422+ } ,
3423+ } ) ,
3424+ ) ;
3425+ fs . writeFileSync (
3426+ path . join ( tmpDir , 'vite.config.ts' ) ,
3427+ [
3428+ "import { defineConfig } from 'vite-plus';" ,
3429+ "import { playwright } from 'vite-plus/test/browser-playwright';" ,
3430+ 'export default defineConfig({ test: { browser: { enabled: true, provider: playwright() } } });' ,
3431+ ] . join ( '\n' ) ,
3432+ ) ;
3433+ fs . writeFileSync (
3434+ path . join ( tmpDir , 'pnpm-workspace.yaml' ) ,
3435+ [
3436+ 'catalog:' ,
3437+ ' vite-plus: latest' ,
3438+ ' vite: npm:@voidzero-dev/vite-plus-core@latest' ,
3439+ 'overrides:' ,
3440+ " vite: 'catalog:'" ,
3441+ 'peerDependencyRules:' ,
3442+ ' allowAny: [vite]' ,
3443+ ' allowedVersions:' ,
3444+ " vite: '*'" ,
3445+ '' ,
3446+ ] . join ( '\n' ) ,
3447+ ) ;
3448+
3449+ expect ( detectVitePlusBootstrapPending ( tmpDir , PackageManager . pnpm ) ) . toBe ( true ) ;
3450+ ensureVitePlusBootstrap ( makeWorkspaceInfo ( tmpDir , PackageManager . pnpm ) ) ;
3451+
3452+ const pkg = readJson ( path . join ( tmpDir , 'package.json' ) ) as {
3453+ devDependencies : Record < string , string > ;
3454+ } ;
3455+ expect ( pkg . devDependencies ) . not . toHaveProperty ( 'playwright' ) ;
3456+ expect ( pkg . devDependencies . vitest ) . toBe ( 'catalog:' ) ;
3457+ expect ( pkg . devDependencies [ '@vitest/browser-playwright' ] ) . toBe ( 'catalog:' ) ;
3458+ expect ( detectVitePlusBootstrapPending ( tmpDir , PackageManager . pnpm ) ) . toBe ( false ) ;
3459+ } ) ;
3460+
34123461 it ( 'references the catalog for an installed browser provider the injection adds to the catalog' , ( ) => {
34133462 // #2005: a workspace package uses `@vitest/browser-playwright` only through a
34143463 // Vite+ shim (no dep), so migration ADDS the provider to the default catalog.
0 commit comments