@playwright/test 1.37.0-alpha-aug-2-2023 → 1.37.0-alpha-aug-4-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/cli.js CHANGED
@@ -169,7 +169,9 @@ async function mergeReports(reportDir, opts) {
169
169
  const configLoader = new _configLoader.ConfigLoader();
170
170
  const config = await (configFile ? configLoader.loadConfigFile(configFile) : configLoader.loadEmptyConfig(process.cwd()));
171
171
  const dir = _path.default.resolve(process.cwd(), reportDir || '');
172
- if (!(await _fs.default.promises.stat(dir)).isDirectory()) throw new Error('Directory does not exist: ' + dir);
172
+ const dirStat = await _fs.default.promises.stat(dir).catch(e => null);
173
+ if (!dirStat) throw new Error('Directory does not exist: ' + dir);
174
+ if (!dirStat.isDirectory()) throw new Error(`"${dir}" is not a directory`);
173
175
  let reporterDescriptions = resolveReporterOption(opts.reporter);
174
176
  if (!reporterDescriptions && configFile) reporterDescriptions = config.config.reporter;
175
177
  if (!reporterDescriptions) reporterDescriptions = [[_config.defaultReporter]];
@@ -243,15 +245,18 @@ function restartWithExperimentalTsEsm(configFile) {
243
245
  if (nodeVersion < 16) return false;
244
246
  if (!configFile) return false;
245
247
  if (process.env.PW_DISABLE_TS_ESM) return false;
246
- if (process.env.PW_TS_ESM_ON) return false;
248
+ if (process.env.PW_TS_ESM_ON) {
249
+ // clear execArgv after restart, so that childProcess.fork in user code does not inherit our loader.
250
+ process.execArgv = (0, _util.execArgvWithoutExperimentalLoaderOptions)();
251
+ return false;
252
+ }
247
253
  if (!(0, _util.fileIsModule)(configFile)) return false;
248
- const NODE_OPTIONS = (process.env.NODE_OPTIONS || '') + (0, _util.experimentalLoaderOption)();
249
254
  const innerProcess = require('child_process').fork(require.resolve('./cli'), process.argv.slice(2), {
250
255
  env: {
251
256
  ...process.env,
252
- NODE_OPTIONS,
253
257
  PW_TS_ESM_ON: '1'
254
- }
258
+ },
259
+ execArgv: (0, _util.execArgvWithExperimentalLoaderOptions)()
255
260
  });
256
261
  innerProcess.on('close', code => {
257
262
  if (code !== 0 && code !== null) (0, _utils.gracefullyProcessExitDoNotHang)(code);
@@ -43,6 +43,9 @@ sendMessageToParent({
43
43
  process.on('disconnect', gracefullyCloseAndExit);
44
44
  process.on('SIGINT', () => {});
45
45
  process.on('SIGTERM', () => {});
46
+
47
+ // Clear execArgv immediately, so that the user-code does not inherit our loader.
48
+ process.execArgv = (0, _util.execArgvWithoutExperimentalLoaderOptions)();
46
49
  let processRunner;
47
50
  let processName;
48
51
  const startingEnv = {
@@ -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, _util.sanitizeForFilePath)((0, _util.trimLongString)(fullTitleWithoutSpec)) + '.' + anonymousSnapshotExtension;
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;
@@ -8,7 +8,6 @@ var _path = _interopRequireDefault(require("path"));
8
8
  var _net = _interopRequireDefault(require("net"));
9
9
  var _utilsBundle = require("playwright-core/lib/utilsBundle");
10
10
  var _utils = require("playwright-core/lib/utils");
11
- var _util = require("../util");
12
11
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
12
  /**
14
13
  * Copyright (c) Microsoft Corporation.
@@ -79,7 +78,6 @@ class WebServerPlugin {
79
78
  command: this._options.command,
80
79
  env: {
81
80
  ...DEFAULT_ENVIRONMENT_VARIABLES,
82
- ...(0, _util.envWithoutExperimentalLoaderOptions)(),
83
81
  ...this._options.env
84
82
  },
85
83
  cwd: this._options.cwd,
@@ -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 currentVersion = 1;
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: currentVersion,
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 ${reportName + '.zip'}: ` + e.message);
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, reportName + '.zip');
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, reportName + '.jsonl');
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;
@@ -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, _util.sanitizeForFilePath)(_path.default.extname(a.name).replace(/^\./, '')) || _utilsBundle.mime.getExtension(a.contentType) || 'dat';
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 {
@@ -10,6 +10,8 @@ var _teleReceiver = require("../isomorphic/teleReceiver");
10
10
  var _reporters = require("../runner/reporters");
11
11
  var _multiplexer = require("./multiplexer");
12
12
  var _utils = require("playwright-core/lib/utils");
13
+ var _blob = require("./blob");
14
+ var _util = require("../util");
13
15
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
16
  /**
15
17
  * Copyright (c) Microsoft Corporation.
@@ -28,13 +30,24 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
28
30
  */
29
31
 
30
32
  async function createMergedReport(config, dir, reporterDescriptions) {
33
+ const reporters = await (0, _reporters.createReporters)(config, 'merge', reporterDescriptions);
34
+ const multiplexer = new _multiplexer.Multiplexer(reporters);
35
+ const receiver = new _teleReceiver.TeleReporterReceiver(_path.default.sep, multiplexer, false, config.config);
36
+ let printStatus = () => {};
37
+ if (!multiplexer.printsToStdio()) {
38
+ printStatus = printStatusToStdout;
39
+ printStatus(`merging reports from ${dir}`);
40
+ }
31
41
  const shardFiles = await sortedShardFiles(dir);
32
42
  if (shardFiles.length === 0) throw new Error(`No report files found in ${dir}`);
33
- const events = await mergeEvents(dir, shardFiles);
43
+ const events = await mergeEvents(dir, shardFiles, printStatus);
34
44
  patchAttachmentPaths(events, dir);
35
- const reporters = await (0, _reporters.createReporters)(config, 'merge', reporterDescriptions);
36
- const receiver = new _teleReceiver.TeleReporterReceiver(_path.default.sep, new _multiplexer.Multiplexer(reporters), false, config.config);
37
- for (const event of events) await receiver.dispatch(event);
45
+ printStatus(`processing ${events.length} test events`);
46
+ for (const event of events) {
47
+ if (event.method === 'onEnd') printStatus(`building final report`);
48
+ await receiver.dispatch(event);
49
+ if (event.method === 'onEnd') printStatus(`finished building report`);
50
+ }
38
51
  }
39
52
  function patchAttachmentPaths(events, resourceDir) {
40
53
  for (const event of events) {
@@ -48,13 +61,15 @@ function patchAttachmentPaths(events, resourceDir) {
48
61
  function parseEvents(reportJsonl) {
49
62
  return reportJsonl.toString().split('\n').filter(line => line.length).map(line => JSON.parse(line));
50
63
  }
51
- async function extractAndParseReports(dir, shardFiles) {
64
+ async function extractAndParseReports(dir, shardFiles, printStatus) {
52
65
  const shardEvents = [];
53
66
  await _fs.default.promises.mkdir(_path.default.join(dir, 'resources'), {
54
67
  recursive: true
55
68
  });
56
69
  for (const file of shardFiles) {
57
- const zipFile = new _utils.ZipFile(_path.default.join(dir, file));
70
+ const absolutePath = _path.default.join(dir, file);
71
+ printStatus(`extracting: ${(0, _util.relativeFilePath)(absolutePath)}`);
72
+ const zipFile = new _utils.ZipFile(absolutePath);
58
73
  const entryNames = await zipFile.entries();
59
74
  for (const entryName of entryNames) {
60
75
  const content = await zipFile.read(entryName);
@@ -76,14 +91,16 @@ async function extractAndParseReports(dir, shardFiles) {
76
91
  function findMetadata(events, file) {
77
92
  var _events$;
78
93
  if (((_events$ = events[0]) === null || _events$ === void 0 ? void 0 : _events$.method) !== 'onBlobReportMetadata') throw new Error(`No metadata event found in ${file}`);
79
- return events[0].params;
94
+ const metadata = events[0].params;
95
+ if (metadata.version > _blob.currentBlobReportVersion) throw new Error(`Blob report ${file} was created with a newer version of Playwright.`);
96
+ return metadata;
80
97
  }
81
- async function mergeEvents(dir, shardReportFiles) {
98
+ async function mergeEvents(dir, shardReportFiles, printStatus) {
82
99
  const events = [];
83
100
  const configureEvents = [];
84
101
  const beginEvents = [];
85
102
  const endEvents = [];
86
- const shardEvents = await extractAndParseReports(dir, shardReportFiles);
103
+ const shardEvents = await extractAndParseReports(dir, shardReportFiles, printStatus);
87
104
  shardEvents.sort((a, b) => {
88
105
  var _a$metadata$shard$cur, _a$metadata$shard, _b$metadata$shard$cur, _b$metadata$shard;
89
106
  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;
@@ -91,6 +108,7 @@ async function mergeEvents(dir, shardReportFiles) {
91
108
  return shardA - shardB;
92
109
  });
93
110
  const allTestIds = new Set();
111
+ printStatus(`merging events`);
94
112
  for (const {
95
113
  parsedEvents
96
114
  } of shardEvents) {
@@ -183,7 +201,10 @@ function mergeEndEvents(endEvents) {
183
201
  }
184
202
  async function sortedShardFiles(dir) {
185
203
  const files = await _fs.default.promises.readdir(dir);
186
- return files.filter(file => file.startsWith('report-') && file.endsWith('.zip')).sort();
204
+ return files.filter(file => file.startsWith('report') && file.endsWith('.zip')).sort();
205
+ }
206
+ function printStatusToStdout(message) {
207
+ process.stdout.write(`${message}\n`);
187
208
  }
188
209
  class ProjectNamePatcher {
189
210
  constructor(_allTestIds, _projectNameSuffix) {
@@ -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, _util.sanitizeForFilePath)(project.name || 'project') + (i ? '-' + i : '') + '.report');
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) {}
@@ -7,6 +7,7 @@ exports.ProcessHost = void 0;
7
7
  var _child_process = _interopRequireDefault(require("child_process"));
8
8
  var _events = require("events");
9
9
  var _utilsBundle = require("playwright-core/lib/utilsBundle");
10
+ var _util = require("../util");
10
11
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
12
  /**
12
13
  * Copyright Microsoft Corporation. All rights reserved.
@@ -49,7 +50,10 @@ class ProcessHost extends _events.EventEmitter {
49
50
  ...process.env,
50
51
  ...this._extraEnv
51
52
  },
52
- stdio: inheritStdio ? ['ignore', 'inherit', 'inherit', 'ipc'] : ['ignore', 'ignore', process.env.PW_RUNNER_DEBUG ? 'inherit' : 'ignore', 'ipc']
53
+ stdio: inheritStdio ? ['ignore', 'inherit', 'inherit', 'ipc'] : ['ignore', 'ignore', process.env.PW_RUNNER_DEBUG ? 'inherit' : 'ignore', 'ipc'],
54
+ ...(process.env.PW_TS_ESM_ON ? {
55
+ execArgv: (0, _util.execArgvWithExperimentalLoaderOptions)()
56
+ } : {})
53
57
  });
54
58
  this.process.on('exit', (code, signal) => {
55
59
  this.didExit = true;
@@ -72,7 +72,7 @@ async function createReporters(config, mode, descriptions) {
72
72
  if (reporters.length && !someReporterPrintsToStdio) {
73
73
  // Add a line/dot/list-mode reporter for convenience.
74
74
  // Important to put it first, jsut in case some other reporter stalls onEnd.
75
- if (mode === 'list') reporters.unshift(new ListModeReporter());else reporters.unshift(!process.env.CI ? new _line.default({
75
+ if (mode === 'list') reporters.unshift(new ListModeReporter());else if (mode !== 'merge') reporters.unshift(!process.env.CI ? new _line.default({
76
76
  omitFailures: true
77
77
  }) : new _dot.default());
78
78
  }
package/lib/util.js CHANGED
@@ -10,10 +10,10 @@ exports.createFileMatcher = createFileMatcher;
10
10
  exports.createFileMatcherFromArguments = createFileMatcherFromArguments;
11
11
  exports.createTitleMatcher = createTitleMatcher;
12
12
  exports.debugTest = void 0;
13
- exports.envWithoutExperimentalLoaderOptions = envWithoutExperimentalLoaderOptions;
14
13
  exports.errorWithFile = errorWithFile;
14
+ exports.execArgvWithExperimentalLoaderOptions = execArgvWithExperimentalLoaderOptions;
15
+ exports.execArgvWithoutExperimentalLoaderOptions = execArgvWithoutExperimentalLoaderOptions;
15
16
  exports.expectTypes = expectTypes;
16
- exports.experimentalLoaderOption = experimentalLoaderOption;
17
17
  exports.fileIsModule = fileIsModule;
18
18
  exports.filterStackFile = filterStackFile;
19
19
  exports.filterStackTrace = filterStackTrace;
@@ -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
@@ -287,16 +283,12 @@ function folderIsModule(folder) {
287
283
  // Rely on `require` internal caching logic.
288
284
  return require(packageJsonPath).type === 'module';
289
285
  }
290
- function experimentalLoaderOption() {
291
- return ` --no-warnings --experimental-loader=${_url.default.pathToFileURL(require.resolve('@playwright/test/lib/transform/esmLoader')).toString()}`;
286
+ const kExperimentalLoaderOptions = ['--no-warnings', `--experimental-loader=${_url.default.pathToFileURL(require.resolve('@playwright/test/lib/transform/esmLoader')).toString()}`];
287
+ function execArgvWithExperimentalLoaderOptions() {
288
+ return [...process.execArgv, ...kExperimentalLoaderOptions];
292
289
  }
293
- function envWithoutExperimentalLoaderOptions() {
294
- const substring = experimentalLoaderOption();
295
- const result = {
296
- ...process.env
297
- };
298
- if (result.NODE_OPTIONS) result.NODE_OPTIONS = result.NODE_OPTIONS.replace(substring, '').trim() || undefined;
299
- return result;
290
+ function execArgvWithoutExperimentalLoaderOptions() {
291
+ return process.execArgv.filter(arg => !kExperimentalLoaderOptions.includes(arg));
300
292
  }
301
293
 
302
294
  // This follows the --moduleResolution=bundler strategy from tsc.
@@ -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, _util.sanitizeForFilePath)(fullTitleWithoutSpec));
134
- if (projectInternal.id) testOutputDir += '-' + (0, _util.sanitizeForFilePath)(projectInternal.id);
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, _util.sanitizeForFilePath)((0, _util.trimLongString)(fullTitleWithoutSpec));
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, _util.sanitizeForFilePath)(this.project.name);
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-2-2023",
3
+ "version": "1.37.0-alpha-aug-4-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-2-2023"
44
+ "playwright-core": "1.37.0-alpha-aug-4-2023"
45
45
  },
46
46
  "optionalDependencies": {
47
47
  "fsevents": "2.3.2"
package/types/test.d.ts CHANGED
@@ -3351,7 +3351,10 @@ export interface TestType<TestArgs extends KeyValue, WorkerArgs extends KeyValue
3351
3351
  * ```js
3352
3352
  * test('example test', async ({ page }) => {
3353
3353
  * // ...
3354
- * await test.info().attach('screenshot', { body: await page.screenshot(), contentType: 'image/png' });
3354
+ * await test.info().attach('screenshot', {
3355
+ * body: await page.screenshot(),
3356
+ * contentType: 'image/png',
3357
+ * });
3355
3358
  * });
3356
3359
  * ```
3357
3360
  *
@@ -316,7 +316,9 @@ export interface FullResult {
316
316
  *
317
317
  * ```js
318
318
  * // my-awesome-reporter.ts
319
- * import type { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult } from '@playwright/test/reporter';
319
+ * import type {
320
+ * Reporter, FullConfig, Suite, TestCase, TestResult, FullResult
321
+ * } from '@playwright/test/reporter';
320
322
  *
321
323
  * class MyReporter implements Reporter {
322
324
  * constructor(options: { customOption?: string } = {}) {