@playwright/test 1.37.0-alpha-aug-3-2023 → 1.37.0-alpha-aug-5-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/stringInternPool.js +36 -0
- package/lib/isomorphic/teleReceiver.js +66 -30
- package/lib/matchers/toMatchSnapshot.js +1 -1
- package/lib/plugins/webServerPlugin.js +18 -13
- package/lib/reporters/blob.js +18 -7
- package/lib/reporters/html.js +1 -1
- package/lib/reporters/merge.js +8 -3
- package/lib/reporters/raw.js +1 -2
- package/lib/reporters/teleEmitter.js +2 -2
- package/lib/util.js +2 -6
- package/lib/worker/testInfo.js +4 -4
- package/package.json +2 -2
- package/types/test.d.ts +3 -3
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.StringInternPool = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Copyright (c) Microsoft Corporation.
|
|
9
|
+
*
|
|
10
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
11
|
+
* you may not use this file except in compliance with the License.
|
|
12
|
+
* You may obtain a copy of the License at
|
|
13
|
+
*
|
|
14
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
15
|
+
*
|
|
16
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
17
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
18
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
19
|
+
* See the License for the specific language governing permissions and
|
|
20
|
+
* limitations under the License.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
class StringInternPool {
|
|
24
|
+
constructor() {
|
|
25
|
+
this._stringCache = new Map();
|
|
26
|
+
}
|
|
27
|
+
internString(s) {
|
|
28
|
+
let result = this._stringCache.get(s);
|
|
29
|
+
if (!result) {
|
|
30
|
+
this._stringCache.set(s, s);
|
|
31
|
+
result = s;
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.StringInternPool = StringInternPool;
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.baseFullConfig = exports.TeleTestCase = exports.TeleSuite = exports.TeleReporterReceiver = void 0;
|
|
7
7
|
exports.parseRegexPatterns = parseRegexPatterns;
|
|
8
8
|
exports.serializeRegexPatterns = serializeRegexPatterns;
|
|
9
|
+
var _stringInternPool = require("./stringInternPool");
|
|
9
10
|
/**
|
|
10
11
|
* Copyright (c) Microsoft Corporation.
|
|
11
12
|
*
|
|
@@ -34,6 +35,7 @@ class TeleReporterReceiver {
|
|
|
34
35
|
this._reuseTestCases = void 0;
|
|
35
36
|
this._reportConfig = void 0;
|
|
36
37
|
this._config = void 0;
|
|
38
|
+
this._stringPool = new _stringInternPool.StringInternPool();
|
|
37
39
|
this._rootSuite = new TeleSuite('', 'root');
|
|
38
40
|
this._pathSeparator = pathSeparator;
|
|
39
41
|
this._reporter = reporter;
|
|
@@ -129,7 +131,7 @@ class TeleReporterReceiver {
|
|
|
129
131
|
testResult.retry = payload.retry;
|
|
130
132
|
testResult.workerIndex = payload.workerIndex;
|
|
131
133
|
testResult.parallelIndex = payload.parallelIndex;
|
|
132
|
-
testResult.
|
|
134
|
+
testResult.setStartTimeNumber(payload.startTime);
|
|
133
135
|
testResult.statusEx = 'running';
|
|
134
136
|
(_this$_reporter$onTes = (_this$_reporter2 = this._reporter).onTestBegin) === null || _this$_reporter$onTes === void 0 ? void 0 : _this$_reporter$onTes.call(_this$_reporter2, test, testResult);
|
|
135
137
|
}
|
|
@@ -147,25 +149,16 @@ class TeleReporterReceiver {
|
|
|
147
149
|
result.error = (_result$errors = result.errors) === null || _result$errors === void 0 ? void 0 : _result$errors[0];
|
|
148
150
|
result.attachments = this._parseAttachments(payload.attachments);
|
|
149
151
|
(_this$_reporter$onTes2 = (_this$_reporter3 = this._reporter).onTestEnd) === null || _this$_reporter$onTes2 === void 0 ? void 0 : _this$_reporter$onTes2.call(_this$_reporter3, test, result);
|
|
152
|
+
// Free up the memory as won't see these step ids.
|
|
153
|
+
result.stepMap = new Map();
|
|
150
154
|
}
|
|
151
155
|
_onStepBegin(testId, resultId, payload) {
|
|
152
156
|
var _this$_reporter$onSte, _this$_reporter4;
|
|
153
157
|
const test = this._tests.get(testId);
|
|
154
158
|
const result = test.resultsMap.get(resultId);
|
|
155
159
|
const parentStep = payload.parentStepId ? result.stepMap.get(payload.parentStepId) : undefined;
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
const parentPath = (parentStep === null || parentStep === void 0 ? void 0 : parentStep.titlePath()) || [];
|
|
159
|
-
return [...parentPath, payload.title];
|
|
160
|
-
},
|
|
161
|
-
title: payload.title,
|
|
162
|
-
category: payload.category,
|
|
163
|
-
location: this._absoluteLocation(payload.location),
|
|
164
|
-
parent: parentStep,
|
|
165
|
-
startTime: new Date(payload.startTime),
|
|
166
|
-
duration: -1,
|
|
167
|
-
steps: []
|
|
168
|
-
};
|
|
160
|
+
const location = this._absoluteLocation(payload.location);
|
|
161
|
+
const step = new TeleTestStep(payload, parentStep, location);
|
|
169
162
|
if (parentStep) parentStep.steps.push(step);else result.steps.push(step);
|
|
170
163
|
result.stepMap.set(payload.id, step);
|
|
171
164
|
(_this$_reporter$onSte = (_this$_reporter4 = this._reporter).onStepBegin) === null || _this$_reporter$onSte === void 0 ? void 0 : _this$_reporter$onSte.call(_this$_reporter4, test, result, step);
|
|
@@ -203,6 +196,8 @@ class TeleReporterReceiver {
|
|
|
203
196
|
}
|
|
204
197
|
_onExit() {
|
|
205
198
|
var _this$_reporter$onExi, _this$_reporter10;
|
|
199
|
+
// Free up the memory from the string pool.
|
|
200
|
+
this._stringPool = new _stringInternPool.StringInternPool();
|
|
206
201
|
return (_this$_reporter$onExi = (_this$_reporter10 = this._reporter).onExit) === null || _this$_reporter$onExi === void 0 ? void 0 : _this$_reporter$onExi.call(_this$_reporter10);
|
|
207
202
|
}
|
|
208
203
|
_parseConfig(config) {
|
|
@@ -288,7 +283,7 @@ class TeleReporterReceiver {
|
|
|
288
283
|
}
|
|
289
284
|
_absolutePath(relativePath) {
|
|
290
285
|
if (!relativePath) return relativePath;
|
|
291
|
-
return this._rootDir + this._pathSeparator + relativePath;
|
|
286
|
+
return this._stringPool.internString(this._rootDir + this._pathSeparator + relativePath);
|
|
292
287
|
}
|
|
293
288
|
}
|
|
294
289
|
exports.TeleReporterReceiver = TeleReporterReceiver;
|
|
@@ -368,27 +363,68 @@ class TeleTestCase {
|
|
|
368
363
|
this.resultsMap.clear();
|
|
369
364
|
}
|
|
370
365
|
_createTestResult(id) {
|
|
371
|
-
const result =
|
|
372
|
-
retry: this.results.length,
|
|
373
|
-
parallelIndex: -1,
|
|
374
|
-
workerIndex: -1,
|
|
375
|
-
duration: -1,
|
|
376
|
-
startTime: new Date(),
|
|
377
|
-
stdout: [],
|
|
378
|
-
stderr: [],
|
|
379
|
-
attachments: [],
|
|
380
|
-
status: 'skipped',
|
|
381
|
-
statusEx: 'scheduled',
|
|
382
|
-
steps: [],
|
|
383
|
-
errors: [],
|
|
384
|
-
stepMap: new Map()
|
|
385
|
-
};
|
|
366
|
+
const result = new TeleTestResult(this.results.length);
|
|
386
367
|
this.results.push(result);
|
|
387
368
|
this.resultsMap.set(id, result);
|
|
388
369
|
return result;
|
|
389
370
|
}
|
|
390
371
|
}
|
|
391
372
|
exports.TeleTestCase = TeleTestCase;
|
|
373
|
+
class TeleTestStep {
|
|
374
|
+
constructor(payload, parentStep, location) {
|
|
375
|
+
this.title = void 0;
|
|
376
|
+
this.category = void 0;
|
|
377
|
+
this.location = void 0;
|
|
378
|
+
this.parent = void 0;
|
|
379
|
+
this.duration = -1;
|
|
380
|
+
this.steps = [];
|
|
381
|
+
this._startTime = 0;
|
|
382
|
+
this.title = payload.title;
|
|
383
|
+
this.category = payload.category;
|
|
384
|
+
this.location = location;
|
|
385
|
+
this.parent = parentStep;
|
|
386
|
+
this._startTime = payload.startTime;
|
|
387
|
+
}
|
|
388
|
+
titlePath() {
|
|
389
|
+
var _this$parent;
|
|
390
|
+
const parentPath = ((_this$parent = this.parent) === null || _this$parent === void 0 ? void 0 : _this$parent.titlePath()) || [];
|
|
391
|
+
return [...parentPath, this.title];
|
|
392
|
+
}
|
|
393
|
+
get startTime() {
|
|
394
|
+
return new Date(this._startTime);
|
|
395
|
+
}
|
|
396
|
+
set startTime(value) {
|
|
397
|
+
this._startTime = +value;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
class TeleTestResult {
|
|
401
|
+
constructor(retry) {
|
|
402
|
+
this.retry = void 0;
|
|
403
|
+
this.parallelIndex = -1;
|
|
404
|
+
this.workerIndex = -1;
|
|
405
|
+
this.duration = -1;
|
|
406
|
+
this.stdout = [];
|
|
407
|
+
this.stderr = [];
|
|
408
|
+
this.attachments = [];
|
|
409
|
+
this.status = 'skipped';
|
|
410
|
+
this.steps = [];
|
|
411
|
+
this.errors = [];
|
|
412
|
+
this.error = void 0;
|
|
413
|
+
this.stepMap = new Map();
|
|
414
|
+
this.statusEx = 'scheduled';
|
|
415
|
+
this._startTime = 0;
|
|
416
|
+
this.retry = retry;
|
|
417
|
+
}
|
|
418
|
+
setStartTimeNumber(startTime) {
|
|
419
|
+
this._startTime = startTime;
|
|
420
|
+
}
|
|
421
|
+
get startTime() {
|
|
422
|
+
return new Date(this._startTime);
|
|
423
|
+
}
|
|
424
|
+
set startTime(value) {
|
|
425
|
+
this._startTime = +value;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
392
428
|
const baseFullConfig = {
|
|
393
429
|
forbidOnly: false,
|
|
394
430
|
fullyParallel: false,
|
|
@@ -76,7 +76,7 @@ class SnapshotHelper {
|
|
|
76
76
|
let actualModifier = '';
|
|
77
77
|
if (!name) {
|
|
78
78
|
const fullTitleWithoutSpec = [...testInfo.titlePath.slice(1), ++snapshotNames.anonymousSnapshotIndex].join(' ');
|
|
79
|
-
name = (0,
|
|
79
|
+
name = (0, _utils.sanitizeForFilePath)((0, _util.trimLongString)(fullTitleWithoutSpec)) + '.' + anonymousSnapshotExtension;
|
|
80
80
|
this.snapshotName = name;
|
|
81
81
|
} else {
|
|
82
82
|
const joinedName = Array.isArray(name) ? name.join(_path.default.sep) : name;
|
|
@@ -33,7 +33,7 @@ const DEFAULT_ENVIRONMENT_VARIABLES = {
|
|
|
33
33
|
const debugWebServer = (0, _utilsBundle.debug)('pw:webserver');
|
|
34
34
|
class WebServerPlugin {
|
|
35
35
|
constructor(options, checkPortOnly) {
|
|
36
|
-
this.
|
|
36
|
+
this._isAvailableCallback = void 0;
|
|
37
37
|
this._killProcess = void 0;
|
|
38
38
|
this._processExitedPromise = void 0;
|
|
39
39
|
this._options = void 0;
|
|
@@ -46,7 +46,7 @@ class WebServerPlugin {
|
|
|
46
46
|
async setup(config, configDir, reporter) {
|
|
47
47
|
var _this$_reporter$onStd;
|
|
48
48
|
this._reporter = reporter;
|
|
49
|
-
this.
|
|
49
|
+
this._isAvailableCallback = this._options.url ? getIsAvailableFunction(this._options.url, this._checkPortOnly, !!this._options.ignoreHTTPSErrors, (_this$_reporter$onStd = this._reporter.onStdErr) === null || _this$_reporter$onStd === void 0 ? void 0 : _this$_reporter$onStd.bind(this._reporter)) : undefined;
|
|
50
50
|
this._options.cwd = this._options.cwd ? _path.default.resolve(configDir, this._options.cwd) : configDir;
|
|
51
51
|
try {
|
|
52
52
|
await this._startProcess();
|
|
@@ -61,14 +61,15 @@ class WebServerPlugin {
|
|
|
61
61
|
await ((_this$_killProcess = this._killProcess) === null || _this$_killProcess === void 0 ? void 0 : _this$_killProcess.call(this));
|
|
62
62
|
}
|
|
63
63
|
async _startProcess() {
|
|
64
|
+
var _this$_isAvailableCal;
|
|
64
65
|
let processExitedReject = error => {};
|
|
65
66
|
this._processExitedPromise = new Promise((_, reject) => processExitedReject = reject);
|
|
66
|
-
const isAlreadyAvailable = await this.
|
|
67
|
+
const isAlreadyAvailable = await ((_this$_isAvailableCal = this._isAvailableCallback) === null || _this$_isAvailableCal === void 0 ? void 0 : _this$_isAvailableCal.call(this));
|
|
67
68
|
if (isAlreadyAvailable) {
|
|
68
69
|
var _this$_options$url;
|
|
69
70
|
debugWebServer(`WebServer is already available`);
|
|
70
71
|
if (this._options.reuseExistingServer) return;
|
|
71
|
-
const port = new URL(this._options.url);
|
|
72
|
+
const port = new URL(this._options.url).port;
|
|
72
73
|
throw new Error(`${(_this$_options$url = this._options.url) !== null && _this$_options$url !== void 0 ? _this$_options$url : `http://localhost${port ? ':' + port : ''}`} is already used, make sure that nothing is running on the port/url or set reuseExistingServer:true in config.webServer.`);
|
|
73
74
|
}
|
|
74
75
|
debugWebServer(`Starting WebServer process ${this._options.command}...`);
|
|
@@ -104,20 +105,21 @@ class WebServerPlugin {
|
|
|
104
105
|
});
|
|
105
106
|
}
|
|
106
107
|
async _waitForProcess() {
|
|
108
|
+
if (!this._isAvailableCallback) {
|
|
109
|
+
this._processExitedPromise.catch(() => {});
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
107
112
|
debugWebServer(`Waiting for availability...`);
|
|
108
|
-
await this._waitForAvailability();
|
|
109
|
-
debugWebServer(`WebServer available`);
|
|
110
|
-
}
|
|
111
|
-
async _waitForAvailability() {
|
|
112
113
|
const launchTimeout = this._options.timeout || 60 * 1000;
|
|
113
114
|
const cancellationToken = {
|
|
114
115
|
canceled: false
|
|
115
116
|
};
|
|
116
117
|
const {
|
|
117
118
|
timedOut
|
|
118
|
-
} = await Promise.race([(0, _utils.raceAgainstDeadline)(() => waitFor(this.
|
|
119
|
+
} = await Promise.race([(0, _utils.raceAgainstDeadline)(() => waitFor(this._isAvailableCallback, cancellationToken), (0, _utils.monotonicTime)() + launchTimeout), this._processExitedPromise]);
|
|
119
120
|
cancellationToken.canceled = true;
|
|
120
121
|
if (timedOut) throw new Error(`Timed out waiting ${launchTimeout}ms from config.webServer.`);
|
|
122
|
+
debugWebServer(`WebServer available`);
|
|
121
123
|
}
|
|
122
124
|
}
|
|
123
125
|
exports.WebServerPlugin = WebServerPlugin;
|
|
@@ -188,11 +190,14 @@ const webServerPluginsForConfig = config => {
|
|
|
188
190
|
const shouldSetBaseUrl = !!config.config.webServer;
|
|
189
191
|
const webServerPlugins = [];
|
|
190
192
|
for (const webServerConfig of config.webServers) {
|
|
191
|
-
if (
|
|
192
|
-
|
|
193
|
+
if (webServerConfig.port && webServerConfig.url) throw new Error(`Either 'port' or 'url' should be specified in config.webServer.`);
|
|
194
|
+
let url;
|
|
195
|
+
if (webServerConfig.port || webServerConfig.url) {
|
|
196
|
+
url = webServerConfig.url || `http://localhost:${webServerConfig.port}`;
|
|
193
197
|
|
|
194
|
-
|
|
195
|
-
|
|
198
|
+
// We only set base url when only the port is given. That's a legacy mode we have regrets about.
|
|
199
|
+
if (shouldSetBaseUrl && !webServerConfig.url) process.env.PLAYWRIGHT_TEST_BASE_URL = url;
|
|
200
|
+
}
|
|
196
201
|
webServerPlugins.push(new WebServerPlugin({
|
|
197
202
|
...webServerConfig,
|
|
198
203
|
url
|
package/lib/reporters/blob.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.BlobReporter = void 0;
|
|
6
|
+
exports.currentBlobReportVersion = exports.BlobReporter = void 0;
|
|
7
7
|
var _fs = _interopRequireDefault(require("fs"));
|
|
8
8
|
var _path = _interopRequireDefault(require("path"));
|
|
9
9
|
var _utils = require("playwright-core/lib/utils");
|
|
@@ -29,7 +29,8 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
29
29
|
* limitations under the License.
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
|
-
const
|
|
32
|
+
const currentBlobReportVersion = 1;
|
|
33
|
+
exports.currentBlobReportVersion = currentBlobReportVersion;
|
|
33
34
|
class BlobReporter extends _teleEmitter.TeleReporterEmitter {
|
|
34
35
|
constructor(options) {
|
|
35
36
|
super(message => this._messages.push(message), false);
|
|
@@ -37,13 +38,14 @@ class BlobReporter extends _teleEmitter.TeleReporterEmitter {
|
|
|
37
38
|
this._attachments = [];
|
|
38
39
|
this._options = void 0;
|
|
39
40
|
this._salt = void 0;
|
|
41
|
+
this._reportName = void 0;
|
|
40
42
|
this._options = options;
|
|
41
43
|
this._salt = (0, _utils.createGuid)();
|
|
42
44
|
}
|
|
43
45
|
onConfigure(config) {
|
|
44
46
|
var _config$shard;
|
|
45
47
|
const metadata = {
|
|
46
|
-
version:
|
|
48
|
+
version: currentBlobReportVersion,
|
|
47
49
|
projectSuffix: process.env.PWTEST_BLOB_SUFFIX,
|
|
48
50
|
shard: (_config$shard = config.shard) !== null && _config$shard !== void 0 ? _config$shard : undefined
|
|
49
51
|
};
|
|
@@ -51,6 +53,7 @@ class BlobReporter extends _teleEmitter.TeleReporterEmitter {
|
|
|
51
53
|
method: 'onBlobReportMetadata',
|
|
52
54
|
params: metadata
|
|
53
55
|
});
|
|
56
|
+
this._reportName = this._computeReportName(config);
|
|
54
57
|
super.onConfigure(config);
|
|
55
58
|
}
|
|
56
59
|
async onEnd(result) {
|
|
@@ -60,14 +63,13 @@ class BlobReporter extends _teleEmitter.TeleReporterEmitter {
|
|
|
60
63
|
await _fs.default.promises.mkdir(outputDir, {
|
|
61
64
|
recursive: true
|
|
62
65
|
});
|
|
63
|
-
const reportName = `report-${(0, _utils.createGuid)()}`;
|
|
64
66
|
const zipFile = new _zipBundle.yazl.ZipFile();
|
|
65
67
|
const zipFinishPromise = new _utils.ManualPromise();
|
|
66
68
|
const finishPromise = zipFinishPromise.catch(e => {
|
|
67
|
-
throw new Error(`Failed to write report ${
|
|
69
|
+
throw new Error(`Failed to write report ${this._reportName + '.zip'}: ` + e.message);
|
|
68
70
|
});
|
|
69
71
|
zipFile.on('error', error => zipFinishPromise.reject(error));
|
|
70
|
-
const zipFileName = _path.default.join(outputDir,
|
|
72
|
+
const zipFileName = _path.default.join(outputDir, this._reportName + '.zip');
|
|
71
73
|
zipFile.outputStream.pipe(_fs.default.createWriteStream(zipFileName)).on('close', () => {
|
|
72
74
|
zipFinishPromise.resolve(undefined);
|
|
73
75
|
}).on('error', error => zipFinishPromise.reject(error));
|
|
@@ -83,10 +85,19 @@ class BlobReporter extends _teleEmitter.TeleReporterEmitter {
|
|
|
83
85
|
}
|
|
84
86
|
const lines = this._messages.map(m => JSON.stringify(m) + '\n');
|
|
85
87
|
const content = _stream.Readable.from(lines);
|
|
86
|
-
zipFile.addReadStream(content,
|
|
88
|
+
zipFile.addReadStream(content, this._reportName + '.jsonl');
|
|
87
89
|
zipFile.end();
|
|
88
90
|
await finishPromise;
|
|
89
91
|
}
|
|
92
|
+
_computeReportName(config) {
|
|
93
|
+
let reportName = 'report';
|
|
94
|
+
if (process.env.PWTEST_BLOB_SUFFIX) reportName += (0, _utils.sanitizeForFilePath)(process.env.PWTEST_BLOB_SUFFIX);
|
|
95
|
+
if (config.shard) {
|
|
96
|
+
const paddedNumber = `${config.shard.current}`.padStart(`${config.shard.total}`.length, '0');
|
|
97
|
+
reportName += `-${paddedNumber}`;
|
|
98
|
+
}
|
|
99
|
+
return reportName;
|
|
100
|
+
}
|
|
90
101
|
_serializeAttachments(attachments) {
|
|
91
102
|
return super._serializeAttachments(attachments).map(attachment => {
|
|
92
103
|
if (!attachment.path) return attachment;
|
package/lib/reporters/html.js
CHANGED
|
@@ -401,7 +401,7 @@ class HtmlBuilder {
|
|
|
401
401
|
_fs.default.mkdirSync(_path.default.join(this._reportFolder, 'data'), {
|
|
402
402
|
recursive: true
|
|
403
403
|
});
|
|
404
|
-
const extension = (0,
|
|
404
|
+
const extension = (0, _utils.sanitizeForFilePath)(_path.default.extname(a.name).replace(/^\./, '')) || _utilsBundle.mime.getExtension(a.contentType) || 'dat';
|
|
405
405
|
const sha1 = (0, _utils.calculateSha1)(a.body) + '.' + extension;
|
|
406
406
|
_fs.default.writeFileSync(_path.default.join(this._reportFolder, 'data', sha1), a.body);
|
|
407
407
|
return {
|
package/lib/reporters/merge.js
CHANGED
|
@@ -7,9 +7,11 @@ exports.createMergedReport = createMergedReport;
|
|
|
7
7
|
var _fs = _interopRequireDefault(require("fs"));
|
|
8
8
|
var _path = _interopRequireDefault(require("path"));
|
|
9
9
|
var _teleReceiver = require("../isomorphic/teleReceiver");
|
|
10
|
+
var _stringInternPool = require("../isomorphic/stringInternPool");
|
|
10
11
|
var _reporters = require("../runner/reporters");
|
|
11
12
|
var _multiplexer = require("./multiplexer");
|
|
12
13
|
var _utils = require("playwright-core/lib/utils");
|
|
14
|
+
var _blob = require("./blob");
|
|
13
15
|
var _util = require("../util");
|
|
14
16
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
17
|
/**
|
|
@@ -90,7 +92,9 @@ async function extractAndParseReports(dir, shardFiles, printStatus) {
|
|
|
90
92
|
function findMetadata(events, file) {
|
|
91
93
|
var _events$;
|
|
92
94
|
if (((_events$ = events[0]) === null || _events$ === void 0 ? void 0 : _events$.method) !== 'onBlobReportMetadata') throw new Error(`No metadata event found in ${file}`);
|
|
93
|
-
|
|
95
|
+
const metadata = events[0].params;
|
|
96
|
+
if (metadata.version > _blob.currentBlobReportVersion) throw new Error(`Blob report ${file} was created with a newer version of Playwright.`);
|
|
97
|
+
return metadata;
|
|
94
98
|
}
|
|
95
99
|
async function mergeEvents(dir, shardReportFiles, printStatus) {
|
|
96
100
|
const events = [];
|
|
@@ -198,7 +202,7 @@ function mergeEndEvents(endEvents) {
|
|
|
198
202
|
}
|
|
199
203
|
async function sortedShardFiles(dir) {
|
|
200
204
|
const files = await _fs.default.promises.readdir(dir);
|
|
201
|
-
return files.filter(file => file.startsWith('report
|
|
205
|
+
return files.filter(file => file.startsWith('report') && file.endsWith('.zip')).sort();
|
|
202
206
|
}
|
|
203
207
|
function printStatusToStdout(message) {
|
|
204
208
|
process.stdout.write(`${message}\n`);
|
|
@@ -206,6 +210,7 @@ function printStatusToStdout(message) {
|
|
|
206
210
|
class ProjectNamePatcher {
|
|
207
211
|
constructor(_allTestIds, _projectNameSuffix) {
|
|
208
212
|
this._testIds = new Set();
|
|
213
|
+
this._stringPool = new _stringInternPool.StringInternPool();
|
|
209
214
|
this._allTestIds = _allTestIds;
|
|
210
215
|
this._projectNameSuffix = _projectNameSuffix;
|
|
211
216
|
}
|
|
@@ -263,6 +268,6 @@ class ProjectNamePatcher {
|
|
|
263
268
|
// To avoid reporters being confused by clashing test ids, we automatically
|
|
264
269
|
// make them unique and produce a separate test from each blob.
|
|
265
270
|
while (this._allTestIds.has(testId)) testId = testId + '1';
|
|
266
|
-
return testId;
|
|
271
|
+
return this._stringPool.internString(testId);
|
|
267
272
|
}
|
|
268
273
|
}
|
package/lib/reporters/raw.js
CHANGED
|
@@ -7,7 +7,6 @@ exports.default = void 0;
|
|
|
7
7
|
var _fs = _interopRequireDefault(require("fs"));
|
|
8
8
|
var _path = _interopRequireDefault(require("path"));
|
|
9
9
|
var _utils = require("playwright-core/lib/utils");
|
|
10
|
-
var _util = require("../util");
|
|
11
10
|
var _base = require("./base");
|
|
12
11
|
var _json = require("./json");
|
|
13
12
|
var _babelBundle = require("../transform/babelBundle");
|
|
@@ -49,7 +48,7 @@ class RawReporter {
|
|
|
49
48
|
});
|
|
50
49
|
let reportFile;
|
|
51
50
|
for (let i = 0; i < 10; ++i) {
|
|
52
|
-
reportFile = _path.default.join(reportFolder, (0,
|
|
51
|
+
reportFile = _path.default.join(reportFolder, (0, _utils.sanitizeForFilePath)(project.name || 'project') + (i ? '-' + i : '') + '.report');
|
|
53
52
|
try {
|
|
54
53
|
if (_fs.default.existsSync(reportFile)) continue;
|
|
55
54
|
} catch (e) {}
|
|
@@ -203,7 +203,7 @@ class TeleReporterEmitter {
|
|
|
203
203
|
retry: result.retry,
|
|
204
204
|
workerIndex: result.workerIndex,
|
|
205
205
|
parallelIndex: result.parallelIndex,
|
|
206
|
-
startTime: result.startTime
|
|
206
|
+
startTime: +result.startTime
|
|
207
207
|
};
|
|
208
208
|
}
|
|
209
209
|
_serializeResultEnd(result) {
|
|
@@ -231,7 +231,7 @@ class TeleReporterEmitter {
|
|
|
231
231
|
parentStepId: (_step$parent = step.parent) === null || _step$parent === void 0 ? void 0 : _step$parent[idSymbol],
|
|
232
232
|
title: step.title,
|
|
233
233
|
category: step.category,
|
|
234
|
-
startTime: step.startTime
|
|
234
|
+
startTime: +step.startTime,
|
|
235
235
|
location: this._relativeLocation(step.location)
|
|
236
236
|
};
|
|
237
237
|
}
|
package/lib/util.js
CHANGED
|
@@ -27,7 +27,6 @@ exports.normalizeAndSaveAttachment = normalizeAndSaveAttachment;
|
|
|
27
27
|
exports.relativeFilePath = relativeFilePath;
|
|
28
28
|
exports.resolveImportSpecifierExtension = resolveImportSpecifierExtension;
|
|
29
29
|
exports.resolveReporterOutputPath = resolveReporterOutputPath;
|
|
30
|
-
exports.sanitizeForFilePath = sanitizeForFilePath;
|
|
31
30
|
exports.serializeError = serializeError;
|
|
32
31
|
exports.stringifyStackFrames = stringifyStackFrames;
|
|
33
32
|
exports.trimLongString = trimLongString;
|
|
@@ -187,9 +186,6 @@ function expectTypes(receiver, types, matcherName) {
|
|
|
187
186
|
throw new Error(`${matcherName} can be only used with ${typesString} object${types.length > 1 ? 's' : ''}`);
|
|
188
187
|
}
|
|
189
188
|
}
|
|
190
|
-
function sanitizeForFilePath(s) {
|
|
191
|
-
return s.replace(/[\x00-\x2C\x2E-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, '-');
|
|
192
|
-
}
|
|
193
189
|
function trimLongString(s, length = 100) {
|
|
194
190
|
if (s.length <= length) return s;
|
|
195
191
|
const hash = (0, _utils.calculateSha1)(s);
|
|
@@ -203,7 +199,7 @@ function addSuffixToFilePath(filePath, suffix, customExtension, sanitize = false
|
|
|
203
199
|
const ext = _path.default.extname(filePath);
|
|
204
200
|
const name = _path.default.basename(filePath, ext);
|
|
205
201
|
const base = _path.default.join(dirname, name);
|
|
206
|
-
return (sanitize ? sanitizeForFilePath(base) : base) + suffix + (customExtension || ext);
|
|
202
|
+
return (sanitize ? (0, _utils.sanitizeForFilePath)(base) : base) + suffix + (customExtension || ext);
|
|
207
203
|
}
|
|
208
204
|
|
|
209
205
|
/**
|
|
@@ -253,7 +249,7 @@ async function normalizeAndSaveAttachment(outputPath, name, options = {}) {
|
|
|
253
249
|
var _options$contentType;
|
|
254
250
|
const hash = (0, _utils.calculateSha1)(options.path);
|
|
255
251
|
if (!(0, _utils.isString)(name)) throw new Error('"name" should be string.');
|
|
256
|
-
const sanitizedNamePrefix = sanitizeForFilePath(name) + '-';
|
|
252
|
+
const sanitizedNamePrefix = (0, _utils.sanitizeForFilePath)(name) + '-';
|
|
257
253
|
const dest = _path.default.join(outputPath, 'attachments', sanitizedNamePrefix + hash + _path.default.extname(options.path));
|
|
258
254
|
await _fs.default.promises.mkdir(_path.default.dirname(dest), {
|
|
259
255
|
recursive: true
|
package/lib/worker/testInfo.js
CHANGED
|
@@ -130,8 +130,8 @@ class TestInfoImpl {
|
|
|
130
130
|
const relativeTestFilePath = _path.default.relative(this.project.testDir, test._requireFile.replace(/\.(spec|test)\.(js|ts|mjs)$/, ''));
|
|
131
131
|
const sanitizedRelativePath = relativeTestFilePath.replace(process.platform === 'win32' ? new RegExp('\\\\', 'g') : new RegExp('/', 'g'), '-');
|
|
132
132
|
const fullTitleWithoutSpec = test.titlePath().slice(1).join(' ');
|
|
133
|
-
let testOutputDir = (0, _util.trimLongString)(sanitizedRelativePath + '-' + (0,
|
|
134
|
-
if (projectInternal.id) testOutputDir += '-' + (0,
|
|
133
|
+
let testOutputDir = (0, _util.trimLongString)(sanitizedRelativePath + '-' + (0, _utils.sanitizeForFilePath)(fullTitleWithoutSpec));
|
|
134
|
+
if (projectInternal.id) testOutputDir += '-' + (0, _utils.sanitizeForFilePath)(projectInternal.id);
|
|
135
135
|
if (this.retry) testOutputDir += '-retry' + this.retry;
|
|
136
136
|
if (this.repeatEachIndex) testOutputDir += '-repeat' + this.repeatEachIndex;
|
|
137
137
|
return _path.default.join(this.project.outputDir, testOutputDir);
|
|
@@ -364,14 +364,14 @@ class TestInfoImpl {
|
|
|
364
364
|
}
|
|
365
365
|
_fsSanitizedTestName() {
|
|
366
366
|
const fullTitleWithoutSpec = this.titlePath.slice(1).join(' ');
|
|
367
|
-
return (0,
|
|
367
|
+
return (0, _utils.sanitizeForFilePath)((0, _util.trimLongString)(fullTitleWithoutSpec));
|
|
368
368
|
}
|
|
369
369
|
snapshotPath(...pathSegments) {
|
|
370
370
|
const subPath = _path.default.join(...pathSegments);
|
|
371
371
|
const parsedSubPath = _path.default.parse(subPath);
|
|
372
372
|
const relativeTestFilePath = _path.default.relative(this.project.testDir, this._test._requireFile);
|
|
373
373
|
const parsedRelativeTestFilePath = _path.default.parse(relativeTestFilePath);
|
|
374
|
-
const projectNamePathSegment = (0,
|
|
374
|
+
const projectNamePathSegment = (0, _utils.sanitizeForFilePath)(this.project.name);
|
|
375
375
|
const snapshotPath = (this._projectInternal.snapshotPathTemplate || '').replace(/\{(.)?testDir\}/g, '$1' + this.project.testDir).replace(/\{(.)?snapshotDir\}/g, '$1' + this.project.snapshotDir).replace(/\{(.)?snapshotSuffix\}/g, this.snapshotSuffix ? '$1' + this.snapshotSuffix : '').replace(/\{(.)?testFileDir\}/g, '$1' + parsedRelativeTestFilePath.dir).replace(/\{(.)?platform\}/g, '$1' + process.platform).replace(/\{(.)?projectName\}/g, projectNamePathSegment ? '$1' + projectNamePathSegment : '').replace(/\{(.)?testName\}/g, '$1' + this._fsSanitizedTestName()).replace(/\{(.)?testFileName\}/g, '$1' + parsedRelativeTestFilePath.base).replace(/\{(.)?testFilePath\}/g, '$1' + relativeTestFilePath).replace(/\{(.)?arg\}/g, '$1' + _path.default.join(parsedSubPath.dir, parsedSubPath.name)).replace(/\{(.)?ext\}/g, parsedSubPath.ext ? '$1' + parsedSubPath.ext : '');
|
|
376
376
|
return _path.default.normalize(_path.default.resolve(this._configInternal.configDir, snapshotPath));
|
|
377
377
|
}
|
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-5-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-5-2023"
|
|
45
45
|
},
|
|
46
46
|
"optionalDependencies": {
|
|
47
47
|
"fsevents": "2.3.2"
|
package/types/test.d.ts
CHANGED
|
@@ -6735,15 +6735,15 @@ interface TestConfigWebServer {
|
|
|
6735
6735
|
command: string;
|
|
6736
6736
|
|
|
6737
6737
|
/**
|
|
6738
|
-
* The port that your http server is expected to appear on. It does wait until it accepts connections.
|
|
6739
|
-
*
|
|
6738
|
+
* The port that your http server is expected to appear on. It does wait until it accepts connections. Either `port`
|
|
6739
|
+
* or `url` should be specified.
|
|
6740
6740
|
*/
|
|
6741
6741
|
port?: number;
|
|
6742
6742
|
|
|
6743
6743
|
/**
|
|
6744
6744
|
* The url on your http server that is expected to return a 2xx, 3xx, 400, 401, 402, or 403 status code when the
|
|
6745
6745
|
* server is ready to accept connections. Redirects (3xx status codes) are being followed and the new location is
|
|
6746
|
-
* checked.
|
|
6746
|
+
* checked. Either `port` or `url` should be specified.
|
|
6747
6747
|
*/
|
|
6748
6748
|
url?: string;
|
|
6749
6749
|
|