@playwright/test 1.37.0-alpha-aug-7-2023 → 1.37.0-alpha-aug-8-2023
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/isomorphic/teleReceiver.js +32 -28
- package/lib/matchers/toMatchSnapshot.js +7 -5
- package/lib/reporters/blob.js +2 -2
- package/lib/reporters/html.js +8 -5
- package/lib/reporters/junit.js +14 -11
- package/lib/reporters/merge.js +46 -75
- package/lib/reporters/teleEmitter.js +7 -3
- package/package.json +2 -2
- package/types/test.d.ts +8 -4
|
@@ -51,8 +51,12 @@ class TeleReporterReceiver {
|
|
|
51
51
|
this._onConfigure(params.config);
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
|
+
if (method === 'onProject') {
|
|
55
|
+
this._onProject(params.project);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
54
58
|
if (method === 'onBegin') {
|
|
55
|
-
this._onBegin(
|
|
59
|
+
this._onBegin();
|
|
56
60
|
return;
|
|
57
61
|
}
|
|
58
62
|
if (method === 'onTestBegin') {
|
|
@@ -92,35 +96,35 @@ class TeleReporterReceiver {
|
|
|
92
96
|
this._config = this._parseConfig(config);
|
|
93
97
|
this._reporter.onConfigure(this._config);
|
|
94
98
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
projectSuite.project = () => p;
|
|
106
|
-
this._mergeSuitesInto(project.suites, projectSuite);
|
|
99
|
+
_onProject(project) {
|
|
100
|
+
let projectSuite = this._rootSuite.suites.find(suite => suite.project().id === project.id);
|
|
101
|
+
if (!projectSuite) {
|
|
102
|
+
projectSuite = new TeleSuite(project.name, 'project');
|
|
103
|
+
this._rootSuite.suites.push(projectSuite);
|
|
104
|
+
projectSuite.parent = this._rootSuite;
|
|
105
|
+
}
|
|
106
|
+
const p = this._parseProject(project);
|
|
107
|
+
projectSuite.project = () => p;
|
|
108
|
+
this._mergeSuitesInto(project.suites, projectSuite);
|
|
107
109
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
110
|
+
// Remove deleted tests when listing. Empty suites will be auto-filtered
|
|
111
|
+
// in the UI layer.
|
|
112
|
+
if (this._listOnly) {
|
|
113
|
+
const testIds = new Set();
|
|
114
|
+
const collectIds = suite => {
|
|
115
|
+
suite.tests.map(t => t.testId).forEach(testId => testIds.add(testId));
|
|
116
|
+
suite.suites.forEach(collectIds);
|
|
117
|
+
};
|
|
118
|
+
project.suites.forEach(collectIds);
|
|
119
|
+
const filterTests = suite => {
|
|
120
|
+
suite.tests = suite.tests.filter(t => testIds.has(t.id));
|
|
121
|
+
suite.suites.forEach(filterTests);
|
|
122
|
+
};
|
|
123
|
+
filterTests(projectSuite);
|
|
123
124
|
}
|
|
125
|
+
}
|
|
126
|
+
_onBegin() {
|
|
127
|
+
var _this$_reporter$onBeg, _this$_reporter;
|
|
124
128
|
(_this$_reporter$onBeg = (_this$_reporter = this._reporter).onBegin) === null || _this$_reporter$onBeg === void 0 ? void 0 : _this$_reporter$onBeg.call(_this$_reporter, this._rootSuite);
|
|
125
129
|
}
|
|
126
130
|
_onTestBegin(testId, payload) {
|
|
@@ -35,7 +35,7 @@ class SnapshotHelper {
|
|
|
35
35
|
var _mime$getType;
|
|
36
36
|
this.testInfo = void 0;
|
|
37
37
|
this.snapshotName = void 0;
|
|
38
|
-
this.
|
|
38
|
+
this.legacyExpectedPath = void 0;
|
|
39
39
|
this.previousPath = void 0;
|
|
40
40
|
this.snapshotPath = void 0;
|
|
41
41
|
this.actualPath = void 0;
|
|
@@ -102,7 +102,7 @@ class SnapshotHelper {
|
|
|
102
102
|
this.snapshotPath = snapshotPathResolver(...inputPathSegments);
|
|
103
103
|
const inputFile = testInfo._getOutputPath(...inputPathSegments);
|
|
104
104
|
const outputFile = testInfo._getOutputPath(...outputPathSegments);
|
|
105
|
-
this.
|
|
105
|
+
this.legacyExpectedPath = (0, _util.addSuffixToFilePath)(inputFile, '-expected');
|
|
106
106
|
this.previousPath = (0, _util.addSuffixToFilePath)(outputFile, '-previous');
|
|
107
107
|
this.actualPath = (0, _util.addSuffixToFilePath)(outputFile, '-actual');
|
|
108
108
|
this.diffPath = (0, _util.addSuffixToFilePath)(outputFile, '-diff');
|
|
@@ -181,13 +181,15 @@ class SnapshotHelper {
|
|
|
181
181
|
if (diffError) output.push(indent(diffError, ' '));
|
|
182
182
|
if (log !== null && log !== void 0 && log.length) output.push((0, _util.callLogText)(log));else output.push('');
|
|
183
183
|
if (expected !== undefined) {
|
|
184
|
-
|
|
184
|
+
// Copy the expectation inside the `test-results/` folder for backwards compatibility,
|
|
185
|
+
// so that one can upload `test-results/` directory and have all the data inside.
|
|
186
|
+
writeFileSync(this.legacyExpectedPath, expected);
|
|
185
187
|
this.testInfo.attachments.push({
|
|
186
188
|
name: (0, _util.addSuffixToFilePath)(this.snapshotName, '-expected'),
|
|
187
189
|
contentType: this.mimeType,
|
|
188
|
-
path: this.
|
|
190
|
+
path: this.snapshotPath
|
|
189
191
|
});
|
|
190
|
-
output.push(`Expected: ${_utilsBundle.colors.yellow(this.
|
|
192
|
+
output.push(`Expected: ${_utilsBundle.colors.yellow(this.snapshotPath)}`);
|
|
191
193
|
}
|
|
192
194
|
if (previous !== undefined) {
|
|
193
195
|
writeFileSync(this.previousPath, previous);
|
package/lib/reporters/blob.js
CHANGED
|
@@ -46,7 +46,7 @@ class BlobReporter extends _teleEmitter.TeleReporterEmitter {
|
|
|
46
46
|
var _config$shard;
|
|
47
47
|
const metadata = {
|
|
48
48
|
version: currentBlobReportVersion,
|
|
49
|
-
|
|
49
|
+
name: process.env.PWTEST_BLOB_REPORT_NAME,
|
|
50
50
|
shard: (_config$shard = config.shard) !== null && _config$shard !== void 0 ? _config$shard : undefined
|
|
51
51
|
};
|
|
52
52
|
this._messages.push({
|
|
@@ -91,7 +91,7 @@ class BlobReporter extends _teleEmitter.TeleReporterEmitter {
|
|
|
91
91
|
}
|
|
92
92
|
_computeReportName(config) {
|
|
93
93
|
let reportName = 'report';
|
|
94
|
-
if (process.env.
|
|
94
|
+
if (process.env.PWTEST_BLOB_REPORT_NAME) reportName += `-${(0, _utils.sanitizeForFilePath)(process.env.PWTEST_BLOB_REPORT_NAME)}`;
|
|
95
95
|
if (config.shard) {
|
|
96
96
|
const paddedNumber = `${config.shard.current}`.padStart(`${config.shard.total}`.length, '0');
|
|
97
97
|
reportName += `-${paddedNumber}`;
|
package/lib/reporters/html.js
CHANGED
|
@@ -187,6 +187,7 @@ class HtmlBuilder {
|
|
|
187
187
|
const data = new Map();
|
|
188
188
|
for (const projectJson of rawReports) {
|
|
189
189
|
for (const file of projectJson.suites) {
|
|
190
|
+
var _projectJson$project$;
|
|
190
191
|
const fileName = file.location.file;
|
|
191
192
|
const fileId = file.fileId;
|
|
192
193
|
let fileEntry = data.get(fileId);
|
|
@@ -211,7 +212,7 @@ class HtmlBuilder {
|
|
|
211
212
|
testFileSummary
|
|
212
213
|
} = fileEntry;
|
|
213
214
|
const testEntries = [];
|
|
214
|
-
this._processJsonSuite(file, fileId, projectJson.project.name, [], testEntries);
|
|
215
|
+
this._processJsonSuite(file, fileId, projectJson.project.name, (_projectJson$project$ = projectJson.project.metadata) === null || _projectJson$project$ === void 0 ? void 0 : _projectJson$project$.reportName, [], testEntries);
|
|
215
216
|
for (const test of testEntries) {
|
|
216
217
|
testFile.tests.push(test.testCase);
|
|
217
218
|
testFileSummary.tests.push(test.testCaseSummary);
|
|
@@ -304,12 +305,12 @@ class HtmlBuilder {
|
|
|
304
305
|
_addDataFile(fileName, data) {
|
|
305
306
|
this._dataZipFile.addBuffer(Buffer.from(JSON.stringify(data)), fileName);
|
|
306
307
|
}
|
|
307
|
-
_processJsonSuite(suite, fileId, projectName, path, outTests) {
|
|
308
|
+
_processJsonSuite(suite, fileId, projectName, reportName, path, outTests) {
|
|
308
309
|
const newPath = [...path, suite.title];
|
|
309
|
-
suite.suites.map(s => this._processJsonSuite(s, fileId, projectName, newPath, outTests));
|
|
310
|
-
suite.tests.forEach(t => outTests.push(this._createTestEntry(t, projectName, newPath)));
|
|
310
|
+
suite.suites.map(s => this._processJsonSuite(s, fileId, projectName, reportName, newPath, outTests));
|
|
311
|
+
suite.tests.forEach(t => outTests.push(this._createTestEntry(t, projectName, reportName, newPath)));
|
|
311
312
|
}
|
|
312
|
-
_createTestEntry(test, projectName, path) {
|
|
313
|
+
_createTestEntry(test, projectName, reportName, path) {
|
|
313
314
|
const duration = test.results.reduce((a, r) => a + r.duration, 0);
|
|
314
315
|
this._tests.set(test.testId, test);
|
|
315
316
|
const location = test.location;
|
|
@@ -321,6 +322,7 @@ class HtmlBuilder {
|
|
|
321
322
|
testId: test.testId,
|
|
322
323
|
title: test.title,
|
|
323
324
|
projectName,
|
|
325
|
+
reportName,
|
|
324
326
|
location,
|
|
325
327
|
duration,
|
|
326
328
|
annotations: test.annotations,
|
|
@@ -333,6 +335,7 @@ class HtmlBuilder {
|
|
|
333
335
|
testId: test.testId,
|
|
334
336
|
title: test.title,
|
|
335
337
|
projectName,
|
|
338
|
+
reportName,
|
|
336
339
|
location,
|
|
337
340
|
duration,
|
|
338
341
|
annotations: test.annotations,
|
package/lib/reporters/junit.js
CHANGED
|
@@ -56,7 +56,7 @@ class JUnitReporter extends _empty.default {
|
|
|
56
56
|
const duration = (0, _utils.monotonicTime)() - this.startTime;
|
|
57
57
|
const children = [];
|
|
58
58
|
for (const projectSuite of this.suite.suites) {
|
|
59
|
-
for (const fileSuite of projectSuite.suites) children.push(this._buildTestSuite(projectSuite.title, fileSuite));
|
|
59
|
+
for (const fileSuite of projectSuite.suites) children.push(await this._buildTestSuite(projectSuite.title, fileSuite));
|
|
60
60
|
}
|
|
61
61
|
const tokens = [];
|
|
62
62
|
const self = this;
|
|
@@ -78,27 +78,27 @@ class JUnitReporter extends _empty.default {
|
|
|
78
78
|
if (this.outputFile) {
|
|
79
79
|
(0, _utils.assert)(this.config.configFile || _path.default.isAbsolute(this.outputFile), 'Expected fully resolved path if not using config file.');
|
|
80
80
|
const outputFile = this.config.configFile ? _path.default.resolve(_path.default.dirname(this.config.configFile), this.outputFile) : this.outputFile;
|
|
81
|
-
_fs.default.
|
|
81
|
+
await _fs.default.promises.mkdir(_path.default.dirname(outputFile), {
|
|
82
82
|
recursive: true
|
|
83
83
|
});
|
|
84
|
-
_fs.default.
|
|
84
|
+
await _fs.default.promises.writeFile(outputFile, reportString);
|
|
85
85
|
} else {
|
|
86
86
|
console.log(reportString);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
-
_buildTestSuite(projectName, suite) {
|
|
89
|
+
async _buildTestSuite(projectName, suite) {
|
|
90
90
|
let tests = 0;
|
|
91
91
|
let skipped = 0;
|
|
92
92
|
let failures = 0;
|
|
93
93
|
let duration = 0;
|
|
94
94
|
const children = [];
|
|
95
|
-
suite.allTests()
|
|
95
|
+
for (const test of suite.allTests()) {
|
|
96
96
|
++tests;
|
|
97
97
|
if (test.outcome() === 'skipped') ++skipped;
|
|
98
98
|
if (!test.ok()) ++failures;
|
|
99
99
|
for (const result of test.results) duration += result.duration;
|
|
100
|
-
this._addTestCase(suite.title, test, children);
|
|
101
|
-
}
|
|
100
|
+
await this._addTestCase(suite.title, test, children);
|
|
101
|
+
}
|
|
102
102
|
this.totalTests += tests;
|
|
103
103
|
this.totalSkipped += skipped;
|
|
104
104
|
this.totalFailures += failures;
|
|
@@ -118,7 +118,7 @@ class JUnitReporter extends _empty.default {
|
|
|
118
118
|
};
|
|
119
119
|
return entry;
|
|
120
120
|
}
|
|
121
|
-
_addTestCase(suiteName, test, entries) {
|
|
121
|
+
async _addTestCase(suiteName, test, entries) {
|
|
122
122
|
var _properties$children2;
|
|
123
123
|
const entry = {
|
|
124
124
|
name: 'testcase',
|
|
@@ -175,10 +175,13 @@ class JUnitReporter extends _empty.default {
|
|
|
175
175
|
systemErr.push(...result.stderr.map(item => item.toString()));
|
|
176
176
|
for (const attachment of result.attachments) {
|
|
177
177
|
if (!attachment.path) continue;
|
|
178
|
+
const attachmentPath = _path.default.relative(this.config.rootDir, attachment.path);
|
|
178
179
|
try {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
} catch
|
|
180
|
+
await _fs.default.promises.access(attachment.path);
|
|
181
|
+
systemOut.push(`\n[[ATTACHMENT|${attachmentPath}]]\n`);
|
|
182
|
+
} catch {
|
|
183
|
+
systemErr.push(`\nWarning: attachment ${attachmentPath} is missing`);
|
|
184
|
+
}
|
|
182
185
|
}
|
|
183
186
|
}
|
|
184
187
|
// Note: it is important to only produce a single system-out/system-err entry
|
package/lib/reporters/merge.js
CHANGED
|
@@ -73,7 +73,7 @@ async function extractAndParseReports(dir, shardFiles, stringPool, printStatus)
|
|
|
73
73
|
printStatus(`extracting: ${(0, _util.relativeFilePath)(absolutePath)}`);
|
|
74
74
|
const zipFile = new _utils.ZipFile(absolutePath);
|
|
75
75
|
const entryNames = await zipFile.entries();
|
|
76
|
-
for (const entryName of entryNames) {
|
|
76
|
+
for (const entryName of entryNames.sort()) {
|
|
77
77
|
const content = await zipFile.read(entryName);
|
|
78
78
|
if (entryName.endsWith('.jsonl')) {
|
|
79
79
|
const parsedEvents = parseEvents(content);
|
|
@@ -82,6 +82,7 @@ async function extractAndParseReports(dir, shardFiles, stringPool, printStatus)
|
|
|
82
82
|
// as a post-processing step.
|
|
83
83
|
internalizer.traverse(parsedEvents);
|
|
84
84
|
shardEvents.push({
|
|
85
|
+
file,
|
|
85
86
|
metadata: findMetadata(parsedEvents, file),
|
|
86
87
|
parsedEvents
|
|
87
88
|
});
|
|
@@ -102,28 +103,47 @@ function findMetadata(events, file) {
|
|
|
102
103
|
return metadata;
|
|
103
104
|
}
|
|
104
105
|
async function mergeEvents(dir, shardReportFiles, printStatus) {
|
|
106
|
+
const stringPool = new _stringInternPool.StringInternPool();
|
|
105
107
|
const events = [];
|
|
106
108
|
const configureEvents = [];
|
|
107
|
-
const
|
|
109
|
+
const projectEvents = [];
|
|
108
110
|
const endEvents = [];
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
const blobs = await extractAndParseReports(dir, shardReportFiles, stringPool, printStatus);
|
|
112
|
+
// Sort by (report name; shard; file name), so that salt generation below is deterministic when:
|
|
113
|
+
// - report names are unique;
|
|
114
|
+
// - report names are missing;
|
|
115
|
+
// - report names are clashing between shards.
|
|
116
|
+
blobs.sort((a, b) => {
|
|
117
|
+
var _a$metadata$name, _b$metadata$name, _a$metadata$shard$cur, _a$metadata$shard, _b$metadata$shard$cur, _b$metadata$shard;
|
|
118
|
+
const nameA = (_a$metadata$name = a.metadata.name) !== null && _a$metadata$name !== void 0 ? _a$metadata$name : '';
|
|
119
|
+
const nameB = (_b$metadata$name = b.metadata.name) !== null && _b$metadata$name !== void 0 ? _b$metadata$name : '';
|
|
120
|
+
if (nameA !== nameB) return nameA.localeCompare(nameB);
|
|
113
121
|
const shardA = (_a$metadata$shard$cur = (_a$metadata$shard = a.metadata.shard) === null || _a$metadata$shard === void 0 ? void 0 : _a$metadata$shard.current) !== null && _a$metadata$shard$cur !== void 0 ? _a$metadata$shard$cur : 0;
|
|
114
122
|
const shardB = (_b$metadata$shard$cur = (_b$metadata$shard = b.metadata.shard) === null || _b$metadata$shard === void 0 ? void 0 : _b$metadata$shard.current) !== null && _b$metadata$shard$cur !== void 0 ? _b$metadata$shard$cur : 0;
|
|
115
|
-
return shardA - shardB;
|
|
123
|
+
if (shardA !== shardB) return shardA - shardB;
|
|
124
|
+
return a.file.localeCompare(b.file);
|
|
116
125
|
});
|
|
117
|
-
const
|
|
126
|
+
const saltSet = new Set();
|
|
118
127
|
printStatus(`merging events`);
|
|
119
128
|
for (const {
|
|
120
|
-
|
|
121
|
-
|
|
129
|
+
file,
|
|
130
|
+
parsedEvents,
|
|
131
|
+
metadata
|
|
132
|
+
} of blobs) {
|
|
133
|
+
// Generate unique salt for each blob.
|
|
134
|
+
const sha1 = (0, _utils.calculateSha1)(metadata.name || _path.default.basename(file)).substring(0, 16);
|
|
135
|
+
let salt = sha1;
|
|
136
|
+
for (let i = 0; saltSet.has(salt); i++) salt = sha1 + '-' + i;
|
|
137
|
+
saltSet.add(salt);
|
|
138
|
+
new IdsPatcher(stringPool, metadata.name, salt).patchEvents(parsedEvents);
|
|
122
139
|
for (const event of parsedEvents) {
|
|
123
|
-
if (event.method === 'onConfigure') configureEvents.push(event);else if (event.method === '
|
|
140
|
+
if (event.method === 'onConfigure') configureEvents.push(event);else if (event.method === 'onProject') projectEvents.push(event);else if (event.method === 'onEnd') endEvents.push(event);else if (event.method !== 'onBlobReportMetadata' && event.method !== 'onBegin') events.push(event);
|
|
124
141
|
}
|
|
125
142
|
}
|
|
126
|
-
return [mergeConfigureEvents(configureEvents),
|
|
143
|
+
return [mergeConfigureEvents(configureEvents), ...projectEvents, {
|
|
144
|
+
method: 'onBegin',
|
|
145
|
+
params: undefined
|
|
146
|
+
}, ...events, mergeEndEvents(endEvents), {
|
|
127
147
|
method: 'onExit',
|
|
128
148
|
params: undefined
|
|
129
149
|
}];
|
|
@@ -150,23 +170,6 @@ function mergeConfigureEvents(configureEvents) {
|
|
|
150
170
|
}
|
|
151
171
|
};
|
|
152
172
|
}
|
|
153
|
-
function mergeBeginEvents(beginEvents) {
|
|
154
|
-
if (!beginEvents.length) throw new Error('No begin events found');
|
|
155
|
-
const projects = [];
|
|
156
|
-
for (const event of beginEvents) {
|
|
157
|
-
const shardProjects = event.params.projects;
|
|
158
|
-
for (const shardProject of shardProjects) {
|
|
159
|
-
const mergedProject = projects.find(p => p.id === shardProject.id);
|
|
160
|
-
if (!mergedProject) projects.push(shardProject);else mergeJsonSuites(shardProject.suites, mergedProject);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
return {
|
|
164
|
-
method: 'onBegin',
|
|
165
|
-
params: {
|
|
166
|
-
projects
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
173
|
function mergeConfigs(to, from) {
|
|
171
174
|
return {
|
|
172
175
|
...to,
|
|
@@ -180,17 +183,6 @@ function mergeConfigs(to, from) {
|
|
|
180
183
|
workers: to.workers + from.workers
|
|
181
184
|
};
|
|
182
185
|
}
|
|
183
|
-
function mergeJsonSuites(jsonSuites, parent) {
|
|
184
|
-
for (const jsonSuite of jsonSuites) {
|
|
185
|
-
const existingSuite = parent.suites.find(s => s.title === jsonSuite.title);
|
|
186
|
-
if (!existingSuite) {
|
|
187
|
-
parent.suites.push(jsonSuite);
|
|
188
|
-
} else {
|
|
189
|
-
mergeJsonSuites(jsonSuite.suites, existingSuite);
|
|
190
|
-
existingSuite.tests.push(...jsonSuite.tests);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
186
|
function mergeEndEvents(endEvents) {
|
|
195
187
|
const result = {
|
|
196
188
|
status: 'passed'
|
|
@@ -213,12 +205,11 @@ async function sortedShardFiles(dir) {
|
|
|
213
205
|
function printStatusToStdout(message) {
|
|
214
206
|
process.stdout.write(`${message}\n`);
|
|
215
207
|
}
|
|
216
|
-
class
|
|
217
|
-
constructor(
|
|
218
|
-
this._testIds = new Set();
|
|
219
|
-
this._allTestIds = _allTestIds;
|
|
208
|
+
class IdsPatcher {
|
|
209
|
+
constructor(_stringPool, _reportName, _salt) {
|
|
220
210
|
this._stringPool = _stringPool;
|
|
221
|
-
this.
|
|
211
|
+
this._reportName = _reportName;
|
|
212
|
+
this._salt = _salt;
|
|
222
213
|
}
|
|
223
214
|
patchEvents(events) {
|
|
224
215
|
for (const event of events) {
|
|
@@ -227,8 +218,8 @@ class ProjectNamePatcher {
|
|
|
227
218
|
params
|
|
228
219
|
} = event;
|
|
229
220
|
switch (method) {
|
|
230
|
-
case '
|
|
231
|
-
this.
|
|
221
|
+
case 'onProject':
|
|
222
|
+
this._onProject(params.project);
|
|
232
223
|
continue;
|
|
233
224
|
case 'onTestBegin':
|
|
234
225
|
case 'onStepBegin':
|
|
@@ -241,39 +232,19 @@ class ProjectNamePatcher {
|
|
|
241
232
|
continue;
|
|
242
233
|
}
|
|
243
234
|
}
|
|
244
|
-
for (const testId of this._testIds) this._allTestIds.add(testId);
|
|
245
|
-
}
|
|
246
|
-
_onBegin(config, projects) {
|
|
247
|
-
for (const project of projects) project.name += this._projectNameSuffix;
|
|
248
|
-
this._updateProjectIds(projects);
|
|
249
|
-
for (const project of projects) project.suites.forEach(suite => this._updateTestIds(suite));
|
|
250
235
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
p.id = candidate;
|
|
258
|
-
usedNames.add(candidate);
|
|
259
|
-
break;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
236
|
+
_onProject(project) {
|
|
237
|
+
var _project$metadata;
|
|
238
|
+
project.metadata = (_project$metadata = project.metadata) !== null && _project$metadata !== void 0 ? _project$metadata : {};
|
|
239
|
+
project.metadata.reportName = this._reportName;
|
|
240
|
+
project.id = this._stringPool.internString(project.id + this._salt);
|
|
241
|
+
project.suites.forEach(suite => this._updateTestIds(suite));
|
|
262
242
|
}
|
|
263
243
|
_updateTestIds(suite) {
|
|
264
|
-
suite.tests.forEach(test =>
|
|
265
|
-
test.testId = this._mapTestId(test.testId);
|
|
266
|
-
this._testIds.add(test.testId);
|
|
267
|
-
});
|
|
244
|
+
suite.tests.forEach(test => test.testId = this._mapTestId(test.testId));
|
|
268
245
|
suite.suites.forEach(suite => this._updateTestIds(suite));
|
|
269
246
|
}
|
|
270
247
|
_mapTestId(testId) {
|
|
271
|
-
|
|
272
|
-
// Consider a setup project running on each shard. In this case we'll have
|
|
273
|
-
// the same testId (from setup project) in multiple blob reports.
|
|
274
|
-
// To avoid reporters being confused by clashing test ids, we automatically
|
|
275
|
-
// make them unique and produce a separate test from each blob.
|
|
276
|
-
while (this._allTestIds.has(testId)) testId = testId + '1';
|
|
277
|
-
return this._stringPool.internString(testId);
|
|
248
|
+
return this._stringPool.internString(testId + this._salt);
|
|
278
249
|
}
|
|
279
250
|
}
|
|
@@ -47,12 +47,16 @@ class TeleReporterEmitter {
|
|
|
47
47
|
}
|
|
48
48
|
onBegin(suite) {
|
|
49
49
|
const projects = suite.suites.map(projectSuite => this._serializeProject(projectSuite));
|
|
50
|
-
this._messageSink({
|
|
51
|
-
method: '
|
|
50
|
+
for (const project of projects) this._messageSink({
|
|
51
|
+
method: 'onProject',
|
|
52
52
|
params: {
|
|
53
|
-
|
|
53
|
+
project
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
|
+
this._messageSink({
|
|
57
|
+
method: 'onBegin',
|
|
58
|
+
params: undefined
|
|
59
|
+
});
|
|
56
60
|
}
|
|
57
61
|
onTestBegin(test, result) {
|
|
58
62
|
result[idSymbol] = (0, _utils.createGuid)();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playwright/test",
|
|
3
|
-
"version": "1.37.0-alpha-aug-
|
|
3
|
+
"version": "1.37.0-alpha-aug-8-2023",
|
|
4
4
|
"description": "A high-level API to automate web browsers",
|
|
5
5
|
"repository": "github:Microsoft/playwright",
|
|
6
6
|
"homepage": "https://playwright.dev",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"license": "Apache-2.0",
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@types/node": "*",
|
|
44
|
-
"playwright-core": "1.37.0-alpha-aug-
|
|
44
|
+
"playwright-core": "1.37.0-alpha-aug-8-2023"
|
|
45
45
|
},
|
|
46
46
|
"optionalDependencies": {
|
|
47
47
|
"fsevents": "2.3.2"
|
package/types/test.d.ts
CHANGED
|
@@ -164,7 +164,7 @@ export interface FullProject<TestArgs = {}, WorkerArgs = {}> {
|
|
|
164
164
|
* Filter to only run tests with a title matching one of the patterns. For example, passing `grep: /cart/` should only
|
|
165
165
|
* run tests with "cart" in the title. Also available globally and in the [command line](https://playwright.dev/docs/test-cli) with the `-g`
|
|
166
166
|
* option. The regular expression will be tested against the string that consists of the test file name,
|
|
167
|
-
* `test.describe` name (if any) and the test name divided by spaces, e.g. `my-test.spec.ts my
|
|
167
|
+
* `test.describe` name (if any) and the test name divided by spaces, e.g. `my-test.spec.ts my-suite my-test`.
|
|
168
168
|
*
|
|
169
169
|
* `grep` option is also useful for [tagging tests](https://playwright.dev/docs/test-annotations#tag-tests).
|
|
170
170
|
*/
|
|
@@ -791,7 +791,9 @@ interface TestConfig {
|
|
|
791
791
|
|
|
792
792
|
/**
|
|
793
793
|
* Filter to only run tests with a title matching one of the patterns. For example, passing `grep: /cart/` should only
|
|
794
|
-
* run tests with "cart" in the title. Also available in the [command line](https://playwright.dev/docs/test-cli) with the `-g` option.
|
|
794
|
+
* run tests with "cart" in the title. Also available in the [command line](https://playwright.dev/docs/test-cli) with the `-g` option. The
|
|
795
|
+
* regular expression will be tested against the string that consists of the test file name, `test.describe` name (if
|
|
796
|
+
* any) and the test name divided by spaces, e.g. `my-test.spec.ts my-suite my-test`.
|
|
795
797
|
*
|
|
796
798
|
* `grep` option is also useful for [tagging tests](https://playwright.dev/docs/test-annotations#tag-tests).
|
|
797
799
|
*
|
|
@@ -1540,7 +1542,9 @@ export interface FullConfig<TestArgs = {}, WorkerArgs = {}> {
|
|
|
1540
1542
|
globalTimeout: number;
|
|
1541
1543
|
/**
|
|
1542
1544
|
* Filter to only run tests with a title matching one of the patterns. For example, passing `grep: /cart/` should only
|
|
1543
|
-
* run tests with "cart" in the title. Also available in the [command line](https://playwright.dev/docs/test-cli) with the `-g` option.
|
|
1545
|
+
* run tests with "cart" in the title. Also available in the [command line](https://playwright.dev/docs/test-cli) with the `-g` option. The
|
|
1546
|
+
* regular expression will be tested against the string that consists of the test file name, `test.describe` name (if
|
|
1547
|
+
* any) and the test name divided by spaces, e.g. `my-test.spec.ts my-suite my-test`.
|
|
1544
1548
|
*
|
|
1545
1549
|
* `grep` option is also useful for [tagging tests](https://playwright.dev/docs/test-annotations#tag-tests).
|
|
1546
1550
|
*
|
|
@@ -6406,7 +6410,7 @@ interface TestProject {
|
|
|
6406
6410
|
* Filter to only run tests with a title matching one of the patterns. For example, passing `grep: /cart/` should only
|
|
6407
6411
|
* run tests with "cart" in the title. Also available globally and in the [command line](https://playwright.dev/docs/test-cli) with the `-g`
|
|
6408
6412
|
* option. The regular expression will be tested against the string that consists of the test file name,
|
|
6409
|
-
* `test.describe` name (if any) and the test name divided by spaces, e.g. `my-test.spec.ts my
|
|
6413
|
+
* `test.describe` name (if any) and the test name divided by spaces, e.g. `my-test.spec.ts my-suite my-test`.
|
|
6410
6414
|
*
|
|
6411
6415
|
* `grep` option is also useful for [tagging tests](https://playwright.dev/docs/test-annotations#tag-tests).
|
|
6412
6416
|
*/
|