Skip to content

Commit b01f434

Browse files
committed
chore: roll playwright to 1.59.0-alpha-2026-03-16
1 parent 9277f5b commit b01f434

11 files changed

Lines changed: 123 additions & 48 deletions

File tree

.claude/skills/roll-playwright.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
name: roll-playwright
3+
description: Roll @playwright/test to the latest next version, build, test, and push a PR branch
4+
user_invocable: true
5+
---
6+
7+
# Roll Playwright Dependency
8+
9+
Follow these steps in order. Stop and report to the user if any step fails.
10+
11+
## 1. Get the latest version
12+
13+
Run `npm info @playwright/test@next version` to get the latest available next version. Save this version string for later.
14+
15+
## 2. Update package.json
16+
17+
Update the `@playwright/test` version in `devDependencies` in `package.json` to the version from step 1.
18+
19+
## 3. Install dependencies
20+
21+
Run `npm i` to update `package-lock.json`.
22+
23+
## 4. Copy reused code
24+
25+
Run `node ./utils/roll-locally`.
26+
27+
## 5. Build
28+
29+
Run `npm run build`.
30+
If this fails, attempt best effort at fixing.
31+
32+
## 6. Test
33+
34+
Run `npm run test -- --project=default`.
35+
If this fails, attempt best effort at fixing.
36+
37+
## 7. Create branch, commit, and push
38+
39+
- Create a new branch named `roll-pwt-<version>` (e.g. `roll-pwt-1.58.2-beta-1770322573000`)
40+
- Stage `package.json` and `package-lock.json`
41+
- Commit with message: `chore: roll playwright to <version>`
42+
- Do NOT add Co-Authored-By to the commit message
43+
- Push the branch to origin

package-lock.json

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@
198198
},
199199
"devDependencies": {
200200
"@babel/preset-typescript": "^7.23.2",
201-
"@playwright/test": "1.58.2-beta-1770322573000",
201+
"@playwright/test": "1.59.0-alpha-2026-03-16",
202202
"@types/babel__core": "^7.20.3",
203203
"@types/babel__helper-plugin-utils": "^7.10.2",
204204
"@types/babel__traverse": "^7.20.3",

src/playwrightTestServer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ export class PlaywrightTestServer {
216216
return;
217217

218218
// Locations are regular expressions.
219-
const locationPatterns = locations ? locations.map(escapeRegex) : undefined;
219+
const locationPatterns = locations ? locations.map(escapeRegex) : [];
220220
const options: Parameters<TestServerInterface['runTests']>['0'] = {
221221
projects: this._model.enabledProjectsFilter(),
222222
locations: locationPatterns,
@@ -344,7 +344,7 @@ export class PlaywrightTestServer {
344344
}
345345

346346
// Locations are regular expressions.
347-
const locationPatterns = locations ? locations.map(escapeRegex) : undefined;
347+
const locationPatterns = locations ? locations.map(escapeRegex) : [];
348348
const options: Parameters<TestServerInterface['runTests']>['0'] = {
349349
projects: this._model.enabledProjectsFilter(),
350350
locations: locationPatterns,

src/testModel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ export class TestModel extends DisposableBase {
710710
if (representsPath)
711711
hasPathItem = true;
712712
else
713-
testIds.push(...collectTestIds(treeItem));
713+
testIds.push(...collectTestIds(treeItem).testIds);
714714
}
715715

716716
// known bug: for a combination of location items, and test IDs outside those locations, those test IDs will never be run.

src/testTree.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export class TestTree extends DisposableBase {
109109
}
110110
}
111111

112-
const upstreamTree = new upstream.TestTree(workspaceFSPath, rootSuite, [], undefined, path.sep);
112+
const upstreamTree = new upstream.TestTree(workspaceFSPath, rootSuite, [], undefined, path.sep, false);
113113
upstreamTree.sortAndPropagateStatus();
114114
upstreamTree.flattenForSingleProject();
115115

src/upstream/testServerInterface.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,14 @@ export interface TestServerInterface {
8383
locations?: string[];
8484
grep?: string;
8585
grepInvert?: string;
86+
onlyChanged?: string;
8687
}): Promise<{
8788
report: ReportEntry[],
8889
status: reporterTypes.FullResult['status']
8990
}>;
9091

9192
runTests(params: {
92-
locations?: string[];
93+
locations: string[];
9394
grep?: string;
9495
grepInvert?: string;
9596
testIds?: string[];

src/upstream/testTree.ts

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export class TestTree {
6464
private _treeItemByTestId = new Map<string, TestItem | TestCaseItem>();
6565
readonly pathSeparator: string;
6666

67-
constructor(rootFolder: string, rootSuite: reporterTypes.Suite | undefined, loadErrors: reporterTypes.TestError[], projectFilters: Map<string, boolean> | undefined, pathSeparator: string) {
67+
constructor(rootFolder: string, rootSuite: reporterTypes.Suite | undefined, loadErrors: reporterTypes.TestError[], projectFilters: Map<string, boolean> | undefined, pathSeparator: string, hideFiles: boolean) {
6868
const filterProjects = projectFilters && [...projectFilters.values()].some(Boolean);
6969
this.pathSeparator = pathSeparator;
7070
this.rootItem = {
@@ -81,11 +81,11 @@ export class TestTree {
8181
};
8282
this._treeItemById.set(rootFolder, this.rootItem);
8383

84-
const visitSuite = (project: reporterTypes.FullProject, parentSuite: reporterTypes.Suite, parentGroup: GroupItem) => {
85-
for (const suite of parentSuite.suites) {
84+
const visitSuite = (project: reporterTypes.FullProject, parentSuite: reporterTypes.Suite, parentGroup: GroupItem, mode: 'tests' | 'suites' | 'all') => {
85+
for (const suite of mode === 'tests' ? [] : parentSuite.suites) {
8686
if (!suite.title) {
8787
// Flatten anonymous describes.
88-
visitSuite(project, suite, parentGroup);
88+
visitSuite(project, suite, parentGroup, 'all');
8989
continue;
9090
}
9191

@@ -105,10 +105,10 @@ export class TestTree {
105105
};
106106
this._addChild(parentGroup, group);
107107
}
108-
visitSuite(project, suite, group);
108+
visitSuite(project, suite, group, 'all');
109109
}
110110

111-
for (const test of parentSuite.tests) {
111+
for (const test of mode === 'suites' ? [] : parentSuite.tests) {
112112
const title = test.title;
113113
let testCaseItem = parentGroup.children.find(t => t.kind !== 'group' && t.title === title) as TestCaseItem;
114114
if (!testCaseItem) {
@@ -167,8 +167,16 @@ export class TestTree {
167167
if (filterProjects && !projectFilters.get(projectSuite.title))
168168
continue;
169169
for (const fileSuite of projectSuite.suites) {
170-
const fileItem = this._fileItem(fileSuite.location!.file.split(pathSeparator), true);
171-
visitSuite(projectSuite.project()!, fileSuite, fileItem);
170+
if (hideFiles) {
171+
visitSuite(projectSuite.project()!, fileSuite, this.rootItem, 'suites');
172+
if (fileSuite.tests.length) {
173+
const defaultDescribeItem = this._defaultDescribeItem();
174+
visitSuite(projectSuite.project()!, fileSuite, defaultDescribeItem, 'tests');
175+
}
176+
} else {
177+
const fileItem = this._fileItem(fileSuite.location!.file.split(pathSeparator), true);
178+
visitSuite(projectSuite.project()!, fileSuite, fileItem, 'all');
179+
}
172180
}
173181
}
174182

@@ -242,6 +250,26 @@ export class TestTree {
242250
return fileItem;
243251
}
244252

253+
private _defaultDescribeItem(): GroupItem {
254+
let defaultDescribeItem = this._treeItemById.get('<anonymous>') as GroupItem;
255+
if (!defaultDescribeItem) {
256+
defaultDescribeItem = {
257+
kind: 'group',
258+
subKind: 'describe',
259+
id: '<anonymous>',
260+
title: '<anonymous>',
261+
location: { file: '', line: 0, column: 0 },
262+
duration: 0,
263+
parent: this.rootItem,
264+
children: [],
265+
status: 'none',
266+
hasLoadErrors: false,
267+
};
268+
this._addChild(this.rootItem, defaultDescribeItem);
269+
}
270+
return defaultDescribeItem;
271+
}
272+
245273
sortAndPropagateStatus() {
246274
sortAndPropagateStatus(this.rootItem);
247275
}
@@ -268,17 +296,6 @@ export class TestTree {
268296
this.rootItem = shortRoot;
269297
}
270298

271-
testIds(): Set<string> {
272-
const result = new Set<string>();
273-
const visit = (treeItem: TreeItem) => {
274-
if (treeItem.kind === 'case')
275-
treeItem.tests.forEach(t => result.add(t.id));
276-
treeItem.children.forEach(visit);
277-
};
278-
visit(this.rootItem);
279-
return result;
280-
}
281-
282299
fileNames(): string[] {
283300
const result = new Set<string>();
284301
const visit = (treeItem: TreeItem) => {
@@ -305,8 +322,8 @@ export class TestTree {
305322
return this._treeItemById.get(id);
306323
}
307324

308-
collectTestIds(treeItem?: TreeItem): Set<string> {
309-
return treeItem ? collectTestIds(treeItem) : new Set();
325+
collectTestIds(treeItem: TreeItem) {
326+
return collectTestIds(treeItem);
310327
}
311328
}
312329

@@ -347,18 +364,27 @@ export function sortAndPropagateStatus(treeItem: TreeItem) {
347364
treeItem.status = 'passed';
348365
}
349366

350-
export function collectTestIds(treeItem: TreeItem): Set<string> {
367+
export function collectTestIds(treeItem: TreeItem): { testIds: Set<string>, locations: Set<string> } {
351368
const testIds = new Set<string>();
369+
const locations = new Set<string>();
352370
const visit = (treeItem: TreeItem) => {
371+
if (treeItem.kind !== 'test' && treeItem.kind !== 'case') {
372+
treeItem.children.forEach(visit);
373+
return;
374+
}
375+
376+
let fileItem: TreeItem = treeItem;
377+
while (fileItem && fileItem.parent && !(fileItem.kind === 'group' && fileItem.subKind === 'file'))
378+
fileItem = fileItem.parent;
379+
locations.add(fileItem.location.file);
380+
353381
if (treeItem.kind === 'case')
354-
treeItem.tests.map(t => t.id).forEach(id => testIds.add(id));
355-
else if (treeItem.kind === 'test')
356-
testIds.add(treeItem.id);
382+
treeItem.tests.forEach(test => testIds.add(test.id));
357383
else
358-
treeItem.children?.forEach(visit);
384+
testIds.add(treeItem.id);
359385
};
360386
visit(treeItem);
361-
return testIds;
387+
return { testIds, locations };
362388
}
363389

364390
export const statusEx = Symbol('statusEx');

tests-integration/tests/baseTest.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export const test = base.extend<TestFixtures>({
5454
`--extensionDevelopmentPath=${path.join(__dirname, '..', '..')}`,
5555
`--extensions-dir=${path.join(defaultCachePath, 'extensions')}`,
5656
`--user-data-dir=${path.join(defaultCachePath, 'user-data')}`,
57+
`--remote-debugging-port=0`,
5758
await createProject(),
5859
],
5960
});
@@ -89,7 +90,7 @@ export const test = base.extend<TestFixtures>({
8990
if (packageManager === 'pnpm-pnp')
9091
await fs.promises.writeFile(path.join(projectPath, '.npmrc'), 'node-linker=pnp');
9192

92-
spawnSync(`${command} --quiet --browser=chromium --gha --install-deps`, {
93+
spawnSync(`${command} --quiet --browser=chromium --gha${process.env.CI ? ' --install-deps' : ''}`, {
9394
cwd: projectPath,
9495
stdio: 'inherit',
9596
shell: true,

tests/mock/vscode.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,10 @@ export class TestRun {
509509
result.push(' Output:');
510510
result.push(...this._renderOutput());
511511
}
512-
return trimLog(result.join(`\n${indent}`)) + `\n${indent}`;
512+
let log = trimLog(result.join(`\n${indent}`)) + `\n${indent}`;
513+
// Strip Playwright's "Context for AI" details block as it contains absolute paths.
514+
log = log.replace(/\n?\s*<br><br><details><summary>Context for AI<\/summary>[\s\S]*?<\/details>/g, '');
515+
return log;
513516
}
514517

515518
renderOutput(): string {

0 commit comments

Comments
 (0)