Skip to content

Commit 1547be9

Browse files
authored
Merge branch 'main' into chore/remove-unused-core-babel-deps
2 parents 34cc545 + 31b0922 commit 1547be9

8 files changed

Lines changed: 187 additions & 13 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "playwright-test-app",
3+
"private": true,
4+
"devDependencies": {
5+
"@playwright/test": "1.60.0",
6+
"@vitest/browser-playwright": "4.1.10",
7+
"@vitest/coverage-v8": "4.1.10",
8+
"vite": "catalog:",
9+
"vite-plus": "catalog:",
10+
"vitest": "catalog:"
11+
},
12+
"devEngines": {
13+
"packageManager": {
14+
"name": "pnpm",
15+
"version": "11.1.1",
16+
"onFail": "download"
17+
}
18+
}
19+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
packages:
2+
- .
3+
catalog:
4+
vite: npm:@voidzero-dev/vite-plus-core@latest
5+
vite-plus: latest
6+
vitest: 4.1.10
7+
overrides:
8+
vite: 'catalog:'
9+
vitest: 'catalog:'
10+
peerDependencyRules:
11+
allowAny:
12+
- vite
13+
- vitest
14+
allowedVersions:
15+
vite: '*'
16+
vitest: '*'
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[[case]]
2+
name = "migration_playwright_test"
3+
vp = "global"
4+
steps = [
5+
{ argv = ["vp", "migrate", "--no-interactive"], comment = "existing Vite+ upgrade: @playwright/test should remain without adding a direct playwright dependency", continue-on-failure = true },
6+
{ argv = ["vpt", "print-file", "package.json"], comment = "@vitest/browser-playwright and @vitest/coverage-v8 should become catalog:", continue-on-failure = true },
7+
{ argv = ["vpt", "print-file", "pnpm-workspace.yaml"], comment = "the default catalog should own the aligned @vitest/* packages", continue-on-failure = true },
8+
]
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# migration_playwright_test
2+
3+
## `vp migrate --no-interactive`
4+
5+
existing Vite+ upgrade: @playwright/test should remain without adding a direct playwright dependency
6+
7+
```
8+
VITE+ - The Unified Toolchain for the Web
9+
10+
◇ Updated . to Vite+ <version>
11+
• Node <version> pnpm <version>
12+
• Dependencies:
13+
vite-plus latest → <version>
14+
vite → <version>
15+
vitest 4.1.10 → <version>
16+
@vitest/browser-playwright 4.1.10 → <version>
17+
@vitest/coverage-v8 4.1.10 → <version>
18+
• Package manager settings configured
19+
```
20+
21+
## `vpt print-file package.json`
22+
23+
@vitest/browser-playwright and @vitest/coverage-v8 should become catalog:
24+
25+
```
26+
{
27+
"name": "playwright-test-app",
28+
"private": true,
29+
"devDependencies": {
30+
"@playwright/test": "1.60.0",
31+
"@vitest/browser-playwright": "catalog:",
32+
"@vitest/coverage-v8": "catalog:",
33+
"vite": "catalog:",
34+
"vite-plus": "catalog:",
35+
"vitest": "catalog:"
36+
},
37+
"devEngines": {
38+
"packageManager": {
39+
"name": "pnpm",
40+
"version": "<version>",
41+
"onFail": "download"
42+
}
43+
}
44+
}
45+
```
46+
47+
## `vpt print-file pnpm-workspace.yaml`
48+
49+
the default catalog should own the aligned @vitest/* packages
50+
51+
```
52+
packages:
53+
- .
54+
catalog:
55+
vite: npm:@voidzero-dev/vite-plus-core@<version>
56+
vite-plus: <version>
57+
vitest: <version>
58+
'@vitest/browser-playwright': <version>
59+
'@vitest/coverage-v8': <version>
60+
overrides:
61+
vite@*: 'catalog:'
62+
vitest@*: 'catalog:'
63+
peerDependencyRules:
64+
allowAny:
65+
- vite
66+
- vitest
67+
allowedVersions:
68+
vite: '*'
69+
vitest: '*'
70+
```

packages/cli/src/migration/__tests__/migrator.spec.ts

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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.

packages/cli/src/migration/migrator/package-json.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
} from '../migrator.ts';
2525
import {
2626
BROWSER_PROVIDER_PEER_DEPS,
27-
findDeclaredSpec,
27+
hasProviderPeerDependency,
2828
resolveProviderPeerSpec,
2929
OPT_IN_BROWSER_PROVIDERS,
3030
OXLINT_PLUGINS_PACKAGE,
@@ -280,8 +280,7 @@ export function rewritePackageJson(
280280
);
281281
}
282282
const peer = BROWSER_PROVIDER_PEER_DEPS[provider]; // 'webdriverio' / 'playwright'
283-
const peerPresent = findDeclaredSpec(pkg, peer);
284-
if (peer && !peerPresent) {
283+
if (!hasProviderPeerDependency(pkg, peer)) {
285284
pkg.devDependencies ??= {};
286285
pkg.devDependencies[peer] = resolveProviderPeerSpec(
287286
pkg,

packages/cli/src/migration/migrator/shared.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,14 @@ export const BROWSER_PROVIDER_PEER_DEPS: Record<string, string> = {
8282
'@vitest/browser-webdriverio': 'webdriverio',
8383
};
8484

85+
// Packages that include runtime peer as a dependency.
86+
const RUNTIME_PEER_INCLUDED_BY: Record<string, readonly string[]> = {
87+
playwright: ['@playwright/test'],
88+
};
89+
8590
// Lockstep sibling packages whose declared version a browser provider's runtime
8691
// framework peer should reuse (they publish together). Keyed by the peer name.
8792
export const PROVIDER_PEER_VERSION_SIBLINGS: Record<string, readonly string[]> = {
88-
playwright: ['@playwright/test'],
8993
webdriverio: ['@wdio/cli', '@wdio/globals'],
9094
};
9195

@@ -99,6 +103,17 @@ export function findDeclaredSpec(pkg: DependencyBag, name: string): string | und
99103
);
100104
}
101105

106+
// A provider's runtime peer is available when declared directly or included by
107+
// another declared package.
108+
export function hasProviderPeerDependency(pkg: DependencyBag, runtimePeer: string): boolean {
109+
return (
110+
findDeclaredSpec(pkg, runtimePeer) !== undefined ||
111+
(RUNTIME_PEER_INCLUDED_BY[runtimePeer] ?? []).some(
112+
(packageName) => findDeclaredSpec(pkg, packageName) !== undefined,
113+
)
114+
);
115+
}
116+
102117
// A deterministic spec for a browser provider's framework peer instead of `*`:
103118
// reference the catalog when it already owns the peer, otherwise reuse a declared
104119
// lockstep sibling's version (concrete, or a catalog reference resolved to its

packages/cli/src/migration/migrator/vite-plus-bootstrap.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import {
5555
import { type DependencyVersionChange, type MigrationReport } from '../report.ts';
5656
import {
5757
BROWSER_PROVIDER_PEER_DEPS,
58+
hasProviderPeerDependency,
5859
resolveProviderPeerSpec,
5960
OPT_IN_BROWSER_PROVIDERS,
6061
REMOVE_PACKAGES,
@@ -405,10 +406,7 @@ function reconcileVitePlusBootstrapPackage(
405406
);
406407
}
407408
const frameworkPeer = BROWSER_PROVIDER_PEER_DEPS[provider];
408-
const frameworkPresent = dependencyGroups.some(
409-
(dependencies) => dependencies?.[frameworkPeer] !== undefined,
410-
);
411-
if (frameworkPeer && !frameworkPresent) {
409+
if (!hasProviderPeerDependency(pkg, frameworkPeer)) {
412410
pkg.devDependencies ??= {};
413411
pkg.devDependencies[frameworkPeer] = resolveProviderPeerSpec(
414412
pkg,

0 commit comments

Comments
 (0)