@playwright/test 1.37.0-alpha-aug-8-2023 → 1.37.0-alpha-aug-9-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.
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.defaultTimeout = exports.defaultReporter = exports.defaultGrep = exports.builtInReporters = exports.FullProjectInternal = exports.FullConfigInternal = void 0;
7
+ exports.getProjectId = getProjectId;
7
8
  exports.takeFirst = takeFirst;
8
9
  exports.toReporters = toReporters;
9
10
  var _fs = _interopRequireDefault(require("fs"));
@@ -135,6 +136,7 @@ class FullConfigInternal {
135
136
  const candidate = name + (i ? i : '');
136
137
  if (usedNames.has(candidate)) continue;
137
138
  p.id = candidate;
139
+ p.project.__projectId = p.id;
138
140
  usedNames.add(candidate);
139
141
  break;
140
142
  }
@@ -143,9 +145,6 @@ class FullConfigInternal {
143
145
  }
144
146
  exports.FullConfigInternal = FullConfigInternal;
145
147
  class FullProjectInternal {
146
- static from(config) {
147
- return config[projectInternalSymbol];
148
- }
149
148
  constructor(configDir, config, fullConfig, projectConfig, configCLIOverrides, throwawayArtifactsPath) {
150
149
  this.project = void 0;
151
150
  this.fullConfig = void 0;
@@ -179,7 +178,6 @@ class FullProjectInternal {
179
178
  dependencies: projectConfig.dependencies || [],
180
179
  teardown: projectConfig.teardown
181
180
  };
182
- this.project[projectInternalSymbol] = this;
183
181
  this.fullyParallel = takeFirst(configCLIOverrides.fullyParallel, projectConfig.fullyParallel, config.fullyParallel, undefined);
184
182
  this.expect = takeFirst(projectConfig.expect, config.expect, {});
185
183
  this.respectGitIgnore = !projectConfig.testDir && !config.testDir;
@@ -252,4 +250,6 @@ exports.defaultGrep = defaultGrep;
252
250
  const defaultReporter = process.env.CI ? 'dot' : 'list';
253
251
  exports.defaultReporter = defaultReporter;
254
252
  const configInternalSymbol = Symbol('configInternalSymbol');
255
- const projectInternalSymbol = Symbol('projectInternalSymbol');
253
+ function getProjectId(project) {
254
+ return project.__projectId;
255
+ }
@@ -97,7 +97,7 @@ class TeleReporterReceiver {
97
97
  this._reporter.onConfigure(this._config);
98
98
  }
99
99
  _onProject(project) {
100
- let projectSuite = this._rootSuite.suites.find(suite => suite.project().id === project.id);
100
+ let projectSuite = this._rootSuite.suites.find(suite => suite.project().__projectId === project.id);
101
101
  if (!projectSuite) {
102
102
  projectSuite = new TeleSuite(project.name, 'project');
103
103
  this._rootSuite.suites.push(projectSuite);
@@ -219,7 +219,7 @@ class TeleReporterReceiver {
219
219
  }
220
220
  _parseProject(project) {
221
221
  return {
222
- id: project.id,
222
+ __projectId: project.id,
223
223
  metadata: project.metadata,
224
224
  name: project.name,
225
225
  outputDir: this._absolutePath(project.outputDir),
@@ -46,6 +46,7 @@ class BlobReporter extends _teleEmitter.TeleReporterEmitter {
46
46
  var _config$shard;
47
47
  const metadata = {
48
48
  version: currentBlobReportVersion,
49
+ userAgent: (0, _utils.getUserAgent)(),
49
50
  name: process.env.PWTEST_BLOB_REPORT_NAME,
50
51
  shard: (_config$shard = config.shard) !== null && _config$shard !== void 0 ? _config$shard : undefined
51
52
  };
@@ -67,7 +67,7 @@ class JSONReporter extends _empty.default {
67
67
  repeatEach: project.repeatEach,
68
68
  retries: project.retries,
69
69
  metadata: project.metadata,
70
- id: _config.FullProjectInternal.from(project).id,
70
+ id: (0, _config.getProjectId)(project),
71
71
  name: project.name,
72
72
  testDir: toPosixPath(project.testDir),
73
73
  testIgnore: serializePatterns(project.testIgnore),
@@ -83,7 +83,7 @@ class JSONReporter extends _empty.default {
83
83
  _mergeSuites(suites) {
84
84
  const fileSuites = new _utils.MultiMap();
85
85
  for (const projectSuite of suites) {
86
- const projectId = _config.FullProjectInternal.from(projectSuite.project()).id;
86
+ const projectId = (0, _config.getProjectId)(projectSuite.project());
87
87
  const projectName = projectSuite.project().name;
88
88
  for (const fileSuite of projectSuite.suites) {
89
89
  const file = fileSuite.location.file;
@@ -34,6 +34,7 @@ async function createMergedReport(config, dir, reporterDescriptions) {
34
34
  const reporters = await (0, _reporters.createReporters)(config, 'merge', reporterDescriptions);
35
35
  const multiplexer = new _multiplexer.Multiplexer(reporters);
36
36
  const receiver = new _teleReceiver.TeleReporterReceiver(_path.default.sep, multiplexer, false, config.config);
37
+ const stringPool = new _stringInternPool.StringInternPool();
37
38
  let printStatus = () => {};
38
39
  if (!multiplexer.printsToStdio()) {
39
40
  printStatus = printStatusToStdout;
@@ -41,14 +42,28 @@ async function createMergedReport(config, dir, reporterDescriptions) {
41
42
  }
42
43
  const shardFiles = await sortedShardFiles(dir);
43
44
  if (shardFiles.length === 0) throw new Error(`No report files found in ${dir}`);
44
- const events = await mergeEvents(dir, shardFiles, printStatus);
45
- patchAttachmentPaths(events, dir);
46
- printStatus(`processing ${events.length} test events`);
47
- for (const event of events) {
48
- if (event.method === 'onEnd') printStatus(`building final report`);
49
- await receiver.dispatch(event);
50
- if (event.method === 'onEnd') printStatus(`finished building report`);
45
+ const eventData = await mergeEvents(dir, shardFiles, stringPool, printStatus);
46
+ printStatus(`processing test events`);
47
+ const dispatchEvents = async events => {
48
+ for (const event of events) {
49
+ if (event.method === 'onEnd') printStatus(`building final report`);
50
+ await receiver.dispatch(event);
51
+ if (event.method === 'onEnd') printStatus(`finished building report`);
52
+ }
53
+ };
54
+ await dispatchEvents(eventData.prologue);
55
+ for (const {
56
+ reportFile,
57
+ idsPatcher
58
+ } of eventData.reports) {
59
+ const reportJsonl = await _fs.default.promises.readFile(reportFile);
60
+ const events = parseTestEvents(reportJsonl);
61
+ new _stringInternPool.JsonStringInternalizer(stringPool).traverse(events);
62
+ idsPatcher.patchEvents(events);
63
+ patchAttachmentPaths(events, dir);
64
+ await dispatchEvents(events);
51
65
  }
66
+ await dispatchEvents(eventData.epilogue);
52
67
  }
53
68
  function patchAttachmentPaths(events, resourceDir) {
54
69
  for (const event of events) {
@@ -59,37 +74,43 @@ function patchAttachmentPaths(events, resourceDir) {
59
74
  }
60
75
  }
61
76
  }
62
- function parseEvents(reportJsonl) {
63
- return reportJsonl.toString().split('\n').filter(line => line.length).map(line => JSON.parse(line));
77
+ const commonEventNames = ['onBlobReportMetadata', 'onConfigure', 'onProject', 'onBegin', 'onEnd'];
78
+ const commonEvents = new Set(commonEventNames);
79
+ const commonEventRegex = new RegExp(`${commonEventNames.join('|')}`);
80
+ function parseCommonEvents(reportJsonl) {
81
+ return reportJsonl.toString().split('\n').filter(line => commonEventRegex.test(line)) // quick filter
82
+ .map(line => JSON.parse(line)).filter(event => commonEvents.has(event.method));
83
+ }
84
+ function parseTestEvents(reportJsonl) {
85
+ return reportJsonl.toString().split('\n').filter(line => line.length).map(line => JSON.parse(line)).filter(event => !commonEvents.has(event.method));
64
86
  }
65
- async function extractAndParseReports(dir, shardFiles, stringPool, printStatus) {
87
+ async function extractAndParseReports(dir, shardFiles, internalizer, printStatus) {
66
88
  const shardEvents = [];
67
89
  await _fs.default.promises.mkdir(_path.default.join(dir, 'resources'), {
68
90
  recursive: true
69
91
  });
70
- const internalizer = new _stringInternPool.JsonStringInternalizer(stringPool);
71
92
  for (const file of shardFiles) {
72
93
  const absolutePath = _path.default.join(dir, file);
73
94
  printStatus(`extracting: ${(0, _util.relativeFilePath)(absolutePath)}`);
74
95
  const zipFile = new _utils.ZipFile(absolutePath);
75
96
  const entryNames = await zipFile.entries();
76
97
  for (const entryName of entryNames.sort()) {
98
+ const fileName = _path.default.join(dir, entryName);
77
99
  const content = await zipFile.read(entryName);
78
100
  if (entryName.endsWith('.jsonl')) {
79
- const parsedEvents = parseEvents(content);
101
+ const parsedEvents = parseCommonEvents(content);
80
102
  // Passing reviver to JSON.parse doesn't work, as the original strings
81
103
  // keep beeing used. To work around that we traverse the parsed events
82
104
  // as a post-processing step.
83
105
  internalizer.traverse(parsedEvents);
84
106
  shardEvents.push({
85
107
  file,
108
+ localPath: fileName,
86
109
  metadata: findMetadata(parsedEvents, file),
87
110
  parsedEvents
88
111
  });
89
- } else {
90
- const fileName = _path.default.join(dir, entryName);
91
- await _fs.default.promises.writeFile(fileName, content);
92
112
  }
113
+ await _fs.default.promises.writeFile(fileName, content);
93
114
  }
94
115
  zipFile.close();
95
116
  }
@@ -102,13 +123,12 @@ function findMetadata(events, file) {
102
123
  if (metadata.version > _blob.currentBlobReportVersion) throw new Error(`Blob report ${file} was created with a newer version of Playwright.`);
103
124
  return metadata;
104
125
  }
105
- async function mergeEvents(dir, shardReportFiles, printStatus) {
106
- const stringPool = new _stringInternPool.StringInternPool();
107
- const events = [];
126
+ async function mergeEvents(dir, shardReportFiles, stringPool, printStatus) {
127
+ const internalizer = new _stringInternPool.JsonStringInternalizer(stringPool);
108
128
  const configureEvents = [];
109
129
  const projectEvents = [];
110
130
  const endEvents = [];
111
- const blobs = await extractAndParseReports(dir, shardReportFiles, stringPool, printStatus);
131
+ const blobs = await extractAndParseReports(dir, shardReportFiles, internalizer, printStatus);
112
132
  // Sort by (report name; shard; file name), so that salt generation below is deterministic when:
113
133
  // - report names are unique;
114
134
  // - report names are missing;
@@ -125,28 +145,41 @@ async function mergeEvents(dir, shardReportFiles, printStatus) {
125
145
  });
126
146
  const saltSet = new Set();
127
147
  printStatus(`merging events`);
148
+ const reports = [];
128
149
  for (const {
129
150
  file,
130
151
  parsedEvents,
131
- metadata
152
+ metadata,
153
+ localPath
132
154
  } of blobs) {
133
155
  // Generate unique salt for each blob.
134
156
  const sha1 = (0, _utils.calculateSha1)(metadata.name || _path.default.basename(file)).substring(0, 16);
135
157
  let salt = sha1;
136
158
  for (let i = 0; saltSet.has(salt); i++) salt = sha1 + '-' + i;
137
159
  saltSet.add(salt);
138
- new IdsPatcher(stringPool, metadata.name, salt).patchEvents(parsedEvents);
160
+ const idsPatcher = new IdsPatcher(stringPool, metadata.name, salt);
161
+ idsPatcher.patchEvents(parsedEvents);
139
162
  for (const event of parsedEvents) {
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);
163
+ if (event.method === 'onConfigure') configureEvents.push(event);else if (event.method === 'onProject') projectEvents.push(event);else if (event.method === 'onEnd') endEvents.push(event);
141
164
  }
165
+
166
+ // Save information about the reports to stream their test events later.
167
+ reports.push({
168
+ idsPatcher,
169
+ reportFile: localPath
170
+ });
142
171
  }
143
- return [mergeConfigureEvents(configureEvents), ...projectEvents, {
144
- method: 'onBegin',
145
- params: undefined
146
- }, ...events, mergeEndEvents(endEvents), {
147
- method: 'onExit',
148
- params: undefined
149
- }];
172
+ return {
173
+ prologue: [mergeConfigureEvents(configureEvents), ...projectEvents, {
174
+ method: 'onBegin',
175
+ params: undefined
176
+ }],
177
+ reports,
178
+ epilogue: [mergeEndEvents(endEvents), {
179
+ method: 'onExit',
180
+ params: undefined
181
+ }]
182
+ };
150
183
  }
151
184
  function mergeConfigureEvents(configureEvents) {
152
185
  if (!configureEvents.length) throw new Error('No configure events found');
@@ -160,7 +160,7 @@ class TeleReporterEmitter {
160
160
  _serializeProject(suite) {
161
161
  const project = suite.project();
162
162
  const report = {
163
- id: _config.FullProjectInternal.from(project).id,
163
+ id: (0, _config.getProjectId)(project),
164
164
  metadata: project.metadata,
165
165
  name: project.name,
166
166
  outputDir: this._relativePath(project.outputDir),
@@ -19,6 +19,7 @@ var _fs = _interopRequireDefault(require("fs"));
19
19
  var _os = _interopRequireDefault(require("os"));
20
20
  var _path = _interopRequireDefault(require("path"));
21
21
  var _utilsBundle = require("../utilsBundle");
22
+ var _utils = require("playwright-core/lib/utils");
22
23
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
23
24
  /**
24
25
  * Copyright (c) Microsoft Corporation.
@@ -95,8 +96,8 @@ function getFromCompilationCache(filename, hash, moduleUrl) {
95
96
  _fs.default.mkdirSync(_path.default.dirname(cachePath), {
96
97
  recursive: true
97
98
  });
98
- if (map) _fs.default.writeFileSync(sourceMapPath, JSON.stringify(map), 'utf8');
99
- _fs.default.writeFileSync(codePath, code, 'utf8');
99
+ if (map) (0, _utils.writeFileSyncAtomic)(sourceMapPath, JSON.stringify(map), 'utf8');
100
+ (0, _utils.writeFileSyncAtomic)(codePath, code, 'utf8');
100
101
  _innerAddToCompilationCache(filename, {
101
102
  codePath,
102
103
  sourceMapPath,
@@ -144,7 +144,7 @@ function transformHook(originalCode, filename, moduleUrl) {
144
144
  cachedCode,
145
145
  addToCache
146
146
  } = (0, _compilationCache.getFromCompilationCache)(filename, hash, moduleUrl);
147
- if (cachedCode) return cachedCode;
147
+ if (cachedCode !== undefined) return cachedCode;
148
148
 
149
149
  // We don't use any browserslist data, but babel checks it anyway.
150
150
  // Silence the annoying warning.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playwright/test",
3
- "version": "1.37.0-alpha-aug-8-2023",
3
+ "version": "1.37.0-alpha-aug-9-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-8-2023"
44
+ "playwright-core": "1.37.0-alpha-aug-9-2023"
45
45
  },
46
46
  "optionalDependencies": {
47
47
  "fsevents": "2.3.2"