@playwright/test 1.31.2 → 1.32.0

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.
Files changed (46) hide show
  1. package/lib/cli.js +12 -34
  2. package/lib/common/compilationCache.js +4 -2
  3. package/lib/common/configLoader.js +4 -1
  4. package/lib/common/fixtures.js +31 -2
  5. package/lib/common/globals.js +9 -0
  6. package/lib/common/process.js +15 -3
  7. package/lib/common/testType.js +2 -1
  8. package/lib/common/transform.js +0 -1
  9. package/lib/index.js +95 -56
  10. package/lib/isomorphic/folders.js +25 -0
  11. package/lib/isomorphic/teleReceiver.js +368 -0
  12. package/lib/matchers/expect.js +35 -16
  13. package/lib/matchers/matchers.js +48 -48
  14. package/lib/matchers/toBeTruthy.js +1 -1
  15. package/lib/matchers/toEqual.js +1 -4
  16. package/lib/matchers/toMatchSnapshot.js +3 -4
  17. package/lib/matchers/toMatchText.js +1 -1
  18. package/lib/plugins/vitePlugin.js +3 -2
  19. package/lib/reporters/base.js +6 -9
  20. package/lib/reporters/html.js +7 -2
  21. package/lib/reporters/json.js +2 -2
  22. package/lib/reporters/junit.js +2 -2
  23. package/lib/reporters/teleEmitter.js +209 -0
  24. package/lib/runner/dispatcher.js +15 -2
  25. package/lib/runner/loadUtils.js +168 -96
  26. package/lib/runner/loaderHost.js +2 -2
  27. package/lib/runner/processHost.js +16 -4
  28. package/lib/runner/reporters.js +3 -2
  29. package/lib/runner/runner.js +9 -1
  30. package/lib/runner/taskRunner.js +6 -8
  31. package/lib/runner/tasks.js +55 -46
  32. package/lib/runner/testGroups.js +15 -10
  33. package/lib/runner/uiMode.js +279 -0
  34. package/lib/runner/workerHost.js +7 -6
  35. package/lib/store.js +99 -0
  36. package/lib/util.js +23 -39
  37. package/lib/worker/fixtureRunner.js +3 -3
  38. package/lib/worker/testInfo.js +8 -3
  39. package/lib/worker/timeoutManager.js +11 -5
  40. package/lib/worker/workerMain.js +6 -3
  41. package/package.json +2 -2
  42. package/types/component.d.ts +1 -1
  43. package/types/reporterPrivate.ts +22 -0
  44. package/types/test.d.ts +18 -22
  45. package/types/testReporter.d.ts +5 -1
  46. package/lib/common/profiler.js +0 -53
@@ -34,7 +34,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
34
34
  * limitations under the License.
35
35
  */
36
36
 
37
- async function createReporter(config, mode) {
37
+ async function createReporter(config, mode, additionalReporters = []) {
38
38
  const defaultReporters = {
39
39
  dot: mode === 'list' ? ListModeReporter : _dot.default,
40
40
  line: mode === 'list' ? ListModeReporter : _line.default,
@@ -43,7 +43,7 @@ async function createReporter(config, mode) {
43
43
  json: _json.default,
44
44
  junit: _junit.default,
45
45
  null: _empty.default,
46
- html: _html.default
46
+ html: mode === 'ui' ? _line.default : _html.default
47
47
  };
48
48
  const reporters = [];
49
49
  if (mode === 'watch') {
@@ -58,6 +58,7 @@ async function createReporter(config, mode) {
58
58
  reporters.push(new reporterConstructor(arg));
59
59
  }
60
60
  }
61
+ reporters.push(...additionalReporters);
61
62
  if (process.env.PW_TEST_REPORTER) {
62
63
  const reporterConstructor = await (0, _loadUtils.loadReporter)(config, process.env.PW_TEST_REPORTER);
63
64
  reporters.push(new reporterConstructor());
@@ -11,6 +11,7 @@ var _reporters = require("./reporters");
11
11
  var _tasks = require("./tasks");
12
12
  var _utilsBundle = require("playwright-core/lib/utilsBundle");
13
13
  var _watchMode = require("./watchMode");
14
+ var _uiMode = require("./uiMode");
14
15
  /**
15
16
  * Copyright 2019 Google Inc. All rights reserved.
16
17
  * Modifications copyright (c) Microsoft Corporation.
@@ -57,7 +58,7 @@ class Runner {
57
58
  factory: p
58
59
  }));
59
60
  const reporter = await (0, _reporters.createReporter)(config, listOnly ? 'list' : 'run');
60
- const taskRunner = listOnly ? (0, _tasks.createTaskRunnerForList)(config, reporter) : (0, _tasks.createTaskRunner)(config, reporter);
61
+ const taskRunner = listOnly ? (0, _tasks.createTaskRunnerForList)(config, reporter, 'in-process') : (0, _tasks.createTaskRunner)(config, reporter);
61
62
  const context = {
62
63
  config,
63
64
  reporter,
@@ -89,6 +90,13 @@ class Runner {
89
90
  }));
90
91
  return await (0, _watchMode.runWatchModeLoop)(config);
91
92
  }
93
+ async uiAllTests() {
94
+ const config = this._config;
95
+ (0, _webServerPlugin.webServerPluginsForConfig)(config).forEach(p => config._internal.plugins.push({
96
+ factory: p
97
+ }));
98
+ return await (0, _uiMode.runUIMode)(config);
99
+ }
92
100
  }
93
101
  exports.Runner = Runner;
94
102
  function sanitizeConfigForJSON(object, visited) {
@@ -41,18 +41,15 @@ class TaskRunner {
41
41
  task
42
42
  });
43
43
  }
44
- stop() {
45
- this._interrupted = true;
46
- }
47
- async run(context, deadline) {
44
+ async run(context, deadline, cancelPromise) {
48
45
  const {
49
46
  status,
50
47
  cleanup
51
- } = await this.runDeferCleanup(context, deadline);
48
+ } = await this.runDeferCleanup(context, deadline, cancelPromise);
52
49
  const teardownStatus = await cleanup();
53
50
  return status === 'passed' ? teardownStatus : status;
54
51
  }
55
- async runDeferCleanup(context, deadline) {
52
+ async runDeferCleanup(context, deadline, cancelPromise = new _utils.ManualPromise()) {
56
53
  const sigintWatcher = new _sigIntWatcher.SigIntWatcher();
57
54
  const timeoutWatcher = new TimeoutWatcher(deadline);
58
55
  const teardownRunner = new TaskRunner(this._reporter, this._globalTimeoutForError);
@@ -89,14 +86,14 @@ class TaskRunner {
89
86
  (0, _utilsBundle.debug)('pw:test:task')(`"${name}" finished`);
90
87
  }
91
88
  };
92
- await Promise.race([taskLoop(), sigintWatcher.promise(), timeoutWatcher.promise]);
89
+ await Promise.race([taskLoop(), cancelPromise, sigintWatcher.promise(), timeoutWatcher.promise]);
93
90
  sigintWatcher.disarm();
94
91
  timeoutWatcher.disarm();
95
92
 
96
93
  // Prevent subsequent tasks from running.
97
94
  this._interrupted = true;
98
95
  let status = 'passed';
99
- if (sigintWatcher.hadSignal()) {
96
+ if (sigintWatcher.hadSignal() || cancelPromise !== null && cancelPromise !== void 0 && cancelPromise.isDone()) {
100
97
  status = 'interrupted';
101
98
  } else if (timeoutWatcher.timedOut()) {
102
99
  var _this$_reporter$onErr2, _this$_reporter2;
@@ -107,6 +104,7 @@ class TaskRunner {
107
104
  } else if (this._hasErrors) {
108
105
  status = 'failed';
109
106
  }
107
+ cancelPromise === null || cancelPromise === void 0 ? void 0 : cancelPromise.resolve();
110
108
  const cleanup = () => teardownRunner.runDeferCleanup(context, deadline).then(r => r.status);
111
109
  return {
112
110
  status,
@@ -15,7 +15,6 @@ var _dispatcher = require("./dispatcher");
15
15
  var _testGroups = require("../runner/testGroups");
16
16
  var _taskRunner = require("./taskRunner");
17
17
  var _loadUtils = require("./loadUtils");
18
- var _util2 = require("../util");
19
18
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
20
19
  /**
21
20
  * Copyright Microsoft Corporation. All rights reserved.
@@ -59,7 +58,7 @@ function addGlobalSetupTasks(taskRunner, config) {
59
58
  taskRunner.addTask('clear output', createRemoveOutputDirsTask());
60
59
  }
61
60
  function addRunTasks(taskRunner, config) {
62
- taskRunner.addTask('create tasks', createTestGroupsTask());
61
+ taskRunner.addTask('create phases', createPhasesTask());
63
62
  taskRunner.addTask('report begin', async ({
64
63
  reporter,
65
64
  rootSuite
@@ -73,9 +72,9 @@ function addRunTasks(taskRunner, config) {
73
72
  taskRunner.addTask('test suite', createRunTestsTask());
74
73
  return taskRunner;
75
74
  }
76
- function createTaskRunnerForList(config, reporter) {
75
+ function createTaskRunnerForList(config, reporter, mode) {
77
76
  const taskRunner = new _taskRunner.TaskRunner(reporter, config.globalTimeout);
78
- taskRunner.addTask('load tests', createLoadTask('in-process', false));
77
+ taskRunner.addTask('load tests', createLoadTask(mode, false));
79
78
  taskRunner.addTask('report begin', async ({
80
79
  reporter,
81
80
  rootSuite
@@ -151,39 +150,49 @@ function createLoadTask(mode, shouldFilterOnly, projectsToIgnore = new Set(), ad
151
150
  const {
152
151
  config
153
152
  } = context;
154
- const cliMatcher = config._internal.cliArgs.length ? (0, _util2.createFileMatcherFromArguments)(config._internal.cliArgs) : () => true;
155
- const fileMatcher = value => cliMatcher(value) && (additionalFileMatcher ? additionalFileMatcher(value) : true);
156
- context.rootSuite = await (0, _loadUtils.loadAllTests)(mode, config, projectsToIgnore, fileMatcher, errors, shouldFilterOnly);
153
+ const filesToRunByProject = await (0, _loadUtils.collectProjectsAndTestFiles)(config, projectsToIgnore, additionalFileMatcher);
154
+ const fileSuitesByProject = await (0, _loadUtils.loadFileSuites)(mode, config, filesToRunByProject, errors);
155
+ context.rootSuite = await (0, _loadUtils.createRootSuite)(config, fileSuitesByProject, errors, shouldFilterOnly);
157
156
  // Fail when no tests.
158
157
  if (!context.rootSuite.allTests().length && !config._internal.passWithNoTests && !config.shard) throw new Error(`No tests found`);
159
158
  };
160
159
  }
161
- function createTestGroupsTask() {
160
+ function createPhasesTask() {
162
161
  return async context => {
163
- const {
164
- config,
165
- rootSuite,
166
- reporter
167
- } = context;
168
162
  context.config._internal.maxConcurrentTestGroups = 0;
169
- for (const phase of buildPhases(rootSuite.suites)) {
170
- // Go over the phases, for each phase create list of task groups.
171
- const projects = [];
172
- for (const projectSuite of phase) {
173
- const testGroups = (0, _testGroups.createTestGroups)(projectSuite, config.workers);
174
- projects.push({
175
- project: projectSuite._projectConfig,
176
- projectSuite,
177
- testGroups
178
- });
163
+ const processed = new Set();
164
+ const projectToSuite = new Map(context.rootSuite.suites.map(suite => [suite.project(), suite]));
165
+ for (let i = 0; i < projectToSuite.size; i++) {
166
+ // Find all projects that have all their dependencies processed by previous phases.
167
+ const phaseProjects = [];
168
+ for (const project of projectToSuite.keys()) {
169
+ if (processed.has(project)) continue;
170
+ if (project._internal.deps.find(p => !processed.has(p))) continue;
171
+ phaseProjects.push(project);
172
+ }
173
+
174
+ // Create a new phase.
175
+ for (const project of phaseProjects) processed.add(project);
176
+ if (phaseProjects.length) {
177
+ let testGroupsInPhase = 0;
178
+ const phase = {
179
+ dispatcher: new _dispatcher.Dispatcher(context.config, context.reporter),
180
+ projects: []
181
+ };
182
+ context.phases.push(phase);
183
+ for (const project of phaseProjects) {
184
+ const projectSuite = projectToSuite.get(project);
185
+ const testGroups = (0, _testGroups.createTestGroups)(projectSuite, context.config.workers);
186
+ phase.projects.push({
187
+ project,
188
+ projectSuite,
189
+ testGroups
190
+ });
191
+ testGroupsInPhase += testGroups.length;
192
+ }
193
+ (0, _utilsBundle.debug)('pw:test:task')(`created phase #${context.phases.length} with ${phase.projects.map(p => p.project.name).sort()} projects, ${testGroupsInPhase} testGroups`);
194
+ context.config._internal.maxConcurrentTestGroups = Math.max(context.config._internal.maxConcurrentTestGroups, testGroupsInPhase);
179
195
  }
180
- const testGroupsInPhase = projects.reduce((acc, project) => acc + project.testGroups.length, 0);
181
- (0, _utilsBundle.debug)('pw:test:task')(`running phase with ${projects.map(p => p.project.name).sort()} projects, ${testGroupsInPhase} testGroups`);
182
- context.phases.push({
183
- dispatcher: new _dispatcher.Dispatcher(config, reporter),
184
- projects
185
- });
186
- context.config._internal.maxConcurrentTestGroups = Math.max(context.config._internal.maxConcurrentTestGroups, testGroupsInPhase);
187
196
  }
188
197
  };
189
198
  }
@@ -204,6 +213,7 @@ function createRunTestsTask() {
204
213
  phases
205
214
  } = context;
206
215
  const successfulProjects = new Set();
216
+ const extraEnvByProjectId = new Map();
207
217
  for (const {
208
218
  dispatcher,
209
219
  projects
@@ -216,6 +226,13 @@ function createRunTestsTask() {
216
226
  project,
217
227
  testGroups
218
228
  } of projects) {
229
+ // Inherit extra enviroment variables from dependencies.
230
+ let extraEnv = {};
231
+ for (const dep of project._internal.deps) extraEnv = {
232
+ ...extraEnv,
233
+ ...extraEnvByProjectId.get(dep._internal.id)
234
+ };
235
+ extraEnvByProjectId.set(project._internal.id, extraEnv);
219
236
  const hasFailedDeps = project._internal.deps.some(p => !successfulProjects.has(p));
220
237
  if (!hasFailedDeps) {
221
238
  phaseTestGroups.push(...testGroups);
@@ -226,8 +243,15 @@ function createRunTestsTask() {
226
243
  }
227
244
  }
228
245
  if (phaseTestGroups.length) {
229
- await dispatcher.run(phaseTestGroups);
246
+ await dispatcher.run(phaseTestGroups, extraEnvByProjectId);
230
247
  await dispatcher.stop();
248
+ for (const [projectId, envProduced] of dispatcher.producedEnvByProjectId()) {
249
+ const extraEnv = extraEnvByProjectId.get(projectId) || {};
250
+ extraEnvByProjectId.set(projectId, {
251
+ ...extraEnv,
252
+ ...envProduced
253
+ });
254
+ }
231
255
  }
232
256
 
233
257
  // If the worker broke, fail everything, we have no way of knowing which
@@ -243,19 +267,4 @@ function createRunTestsTask() {
243
267
  }
244
268
  }
245
269
  };
246
- }
247
- function buildPhases(projectSuites) {
248
- const phases = [];
249
- const processed = new Set();
250
- for (let i = 0; i < projectSuites.length; i++) {
251
- const phase = [];
252
- for (const projectSuite of projectSuites) {
253
- if (processed.has(projectSuite._projectConfig)) continue;
254
- if (projectSuite._projectConfig._internal.deps.find(p => !processed.has(p))) continue;
255
- phase.push(projectSuite);
256
- }
257
- for (const projectSuite of phase) processed.add(projectSuite._projectConfig);
258
- if (phase.length) phases.push(phase);
259
- }
260
- return phases;
261
270
  }
@@ -106,9 +106,16 @@ function createTestGroups(projectSuite, workers) {
106
106
  }
107
107
  return result;
108
108
  }
109
- function filterForShard(shard, filesByProject) {
109
+ function filterForShard(shard, testGroups) {
110
+ // Note that sharding works based on test groups.
111
+ // This means parallel files will be sharded by single tests,
112
+ // while non-parallel files will be sharded by the whole file.
113
+ //
114
+ // Shards are still balanced by the number of tests, not files,
115
+ // even in the case of non-paralleled files.
116
+
110
117
  let shardableTotal = 0;
111
- for (const files of filesByProject.values()) shardableTotal += files.length;
118
+ for (const group of testGroups) shardableTotal += group.tests.length;
112
119
 
113
120
  // Each shard gets some tests.
114
121
  const shardSize = Math.floor(shardableTotal / shard.total);
@@ -118,14 +125,12 @@ function filterForShard(shard, filesByProject) {
118
125
  const from = shardSize * currentShard + Math.min(extraOne, currentShard);
119
126
  const to = from + shardSize + (currentShard < extraOne ? 1 : 0);
120
127
  let current = 0;
121
- const result = new Map();
122
- for (const [project, files] of filesByProject) {
123
- const shardFiles = [];
124
- for (const file of files) {
125
- if (current >= from && current < to) shardFiles.push(file);
126
- ++current;
127
- }
128
- if (shardFiles.length) result.set(project, shardFiles);
128
+ const result = new Set();
129
+ for (const group of testGroups) {
130
+ // Any test group goes to the shard that contains the first test of this group.
131
+ // So, this shard gets any group that starts at [from; to)
132
+ if (current >= from && current < to) result.add(group);
133
+ current += group.tests.length;
129
134
  }
130
135
  return result;
131
136
  }
@@ -0,0 +1,279 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.runUIMode = runUIMode;
7
+ var _server = require("playwright-core/lib/server");
8
+ var _utils = require("playwright-core/lib/utils");
9
+ var _compilationCache = require("../common/compilationCache");
10
+ var _multiplexer = require("../reporters/multiplexer");
11
+ var _teleEmitter = require("../reporters/teleEmitter");
12
+ var _reporters = require("./reporters");
13
+ var _tasks = require("./tasks");
14
+ var _utilsBundle = require("../utilsBundle");
15
+ /**
16
+ * Copyright Microsoft Corporation. All rights reserved.
17
+ *
18
+ * Licensed under the Apache License, Version 2.0 (the "License");
19
+ * you may not use this file except in compliance with the License.
20
+ * You may obtain a copy of the License at
21
+ *
22
+ * http://www.apache.org/licenses/LICENSE-2.0
23
+ *
24
+ * Unless required by applicable law or agreed to in writing, software
25
+ * distributed under the License is distributed on an "AS IS" BASIS,
26
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27
+ * See the License for the specific language governing permissions and
28
+ * limitations under the License.
29
+ */
30
+
31
+ class UIMode {
32
+ constructor(config) {
33
+ this._config = void 0;
34
+ this._page = void 0;
35
+ this._testRun = void 0;
36
+ this.globalCleanup = void 0;
37
+ this._testWatcher = void 0;
38
+ this._originalStderr = void 0;
39
+ this._config = config;
40
+ process.env.PW_LIVE_TRACE_STACKS = '1';
41
+ config._internal.configCLIOverrides.forbidOnly = false;
42
+ config._internal.configCLIOverrides.globalTimeout = 0;
43
+ config._internal.configCLIOverrides.repeatEach = 0;
44
+ config._internal.configCLIOverrides.shard = undefined;
45
+ config._internal.configCLIOverrides.updateSnapshots = undefined;
46
+ config._internal.listOnly = false;
47
+ config._internal.passWithNoTests = true;
48
+ for (const project of config.projects) project._internal.deps = [];
49
+ for (const p of config.projects) p.retries = 0;
50
+ config._internal.configCLIOverrides.use = config._internal.configCLIOverrides.use || {};
51
+ config._internal.configCLIOverrides.use.trace = {
52
+ mode: 'on',
53
+ sources: false
54
+ };
55
+ this._originalStderr = process.stderr.write.bind(process.stderr);
56
+ this._installGlobalWatcher();
57
+ }
58
+ _installGlobalWatcher() {
59
+ const projectDirs = new Set();
60
+ for (const p of this._config.projects) projectDirs.add(p.testDir);
61
+ let coalescingTimer;
62
+ const watcher = _utilsBundle.chokidar.watch([...projectDirs], {
63
+ ignoreInitial: true,
64
+ persistent: true
65
+ }).on('all', async event => {
66
+ if (event !== 'add' && event !== 'change' && event !== 'unlink') return;
67
+ if (coalescingTimer) clearTimeout(coalescingTimer);
68
+ coalescingTimer = setTimeout(() => {
69
+ this._dispatchEvent({
70
+ method: 'listChanged'
71
+ });
72
+ }, 200);
73
+ });
74
+ return watcher;
75
+ }
76
+ async runGlobalSetup() {
77
+ const reporter = await (0, _reporters.createReporter)(this._config, 'watch');
78
+ const taskRunner = (0, _tasks.createTaskRunnerForWatchSetup)(this._config, reporter);
79
+ reporter.onConfigure(this._config);
80
+ const context = {
81
+ config: this._config,
82
+ reporter,
83
+ phases: []
84
+ };
85
+ const {
86
+ status,
87
+ cleanup: globalCleanup
88
+ } = await taskRunner.runDeferCleanup(context, 0);
89
+ if (status !== 'passed') {
90
+ await globalCleanup();
91
+ return status;
92
+ }
93
+ this.globalCleanup = globalCleanup;
94
+ return status;
95
+ }
96
+ async showUI() {
97
+ this._page = await (0, _server.showTraceViewer)([], 'chromium', {
98
+ app: 'watch.html',
99
+ headless: (0, _utils.isUnderTest)() && process.env.PWTEST_HEADED_FOR_TEST !== '1'
100
+ });
101
+ if (!process.env.PWTEST_DEBUG) {
102
+ process.stdout.write = chunk => {
103
+ this._dispatchEvent({
104
+ method: 'stdio',
105
+ params: chunkToPayload('stdout', chunk)
106
+ });
107
+ return true;
108
+ };
109
+ process.stderr.write = chunk => {
110
+ this._dispatchEvent({
111
+ method: 'stdio',
112
+ params: chunkToPayload('stderr', chunk)
113
+ });
114
+ return true;
115
+ };
116
+ }
117
+ const exitPromise = new _utils.ManualPromise();
118
+ this._page.on('close', () => exitPromise.resolve());
119
+ let queue = Promise.resolve();
120
+ this._page.exposeBinding('sendMessage', false, async (source, data) => {
121
+ const {
122
+ method,
123
+ params
124
+ } = data;
125
+ if (method === 'exit') {
126
+ exitPromise.resolve();
127
+ return;
128
+ }
129
+ if (method === 'watch') {
130
+ this._watchFiles(params.fileNames);
131
+ return;
132
+ }
133
+ if (method === 'open' && params.location) {
134
+ (0, _utilsBundle.open)('vscode://file/' + params.location).catch(e => this._originalStderr(String(e)));
135
+ return;
136
+ }
137
+ if (method === 'resizeTerminal') {
138
+ process.stdout.columns = params.cols;
139
+ process.stdout.rows = params.rows;
140
+ process.stderr.columns = params.cols;
141
+ process.stderr.columns = params.rows;
142
+ return;
143
+ }
144
+ if (method === 'stop') {
145
+ this._stopTests();
146
+ return;
147
+ }
148
+ queue = queue.then(() => this._queueListOrRun(method, params));
149
+ await queue;
150
+ });
151
+ await exitPromise;
152
+ }
153
+ async _queueListOrRun(method, params) {
154
+ if (method === 'list') await this._listTests();
155
+ if (method === 'run') await this._runTests(params.testIds);
156
+ }
157
+ _dispatchEvent(message) {
158
+ // eslint-disable-next-line no-console
159
+ this._page.mainFrame().evaluateExpression(dispatchFuncSource, true, message).catch(e => this._originalStderr(String(e)));
160
+ }
161
+ async _listTests() {
162
+ const listReporter = new _teleEmitter.TeleReporterEmitter(e => this._dispatchEvent(e));
163
+ const reporter = new _multiplexer.Multiplexer([listReporter]);
164
+ this._config._internal.listOnly = true;
165
+ this._config._internal.testIdMatcher = undefined;
166
+ const taskRunner = (0, _tasks.createTaskRunnerForList)(this._config, reporter, 'out-of-process');
167
+ const context = {
168
+ config: this._config,
169
+ reporter,
170
+ phases: []
171
+ };
172
+ (0, _compilationCache.clearCompilationCache)();
173
+ reporter.onConfigure(this._config);
174
+ const status = await taskRunner.run(context, 0);
175
+ reporter.onExit({
176
+ status
177
+ });
178
+ }
179
+ async _runTests(testIds) {
180
+ await this._stopTests();
181
+ const testIdSet = testIds ? new Set(testIds) : null;
182
+ this._config._internal.listOnly = false;
183
+ this._config._internal.testIdMatcher = id => !testIdSet || testIdSet.has(id);
184
+ const runReporter = new _teleEmitter.TeleReporterEmitter(e => this._dispatchEvent(e));
185
+ const reporter = await (0, _reporters.createReporter)(this._config, 'ui', [runReporter]);
186
+ const taskRunner = (0, _tasks.createTaskRunnerForWatch)(this._config, reporter);
187
+ const context = {
188
+ config: this._config,
189
+ reporter,
190
+ phases: []
191
+ };
192
+ (0, _compilationCache.clearCompilationCache)();
193
+ reporter.onConfigure(this._config);
194
+ const stop = new _utils.ManualPromise();
195
+ const run = taskRunner.run(context, 0, stop).then(async status => {
196
+ await reporter.onExit({
197
+ status
198
+ });
199
+ this._testRun = undefined;
200
+ this._config._internal.testIdMatcher = undefined;
201
+ return status;
202
+ });
203
+ this._testRun = {
204
+ run,
205
+ stop
206
+ };
207
+ await run;
208
+ }
209
+ async _watchFiles(fileNames) {
210
+ const files = new Set();
211
+ for (const fileName of fileNames) {
212
+ files.add(fileName);
213
+ (0, _compilationCache.dependenciesForTestFile)(fileName).forEach(file => files.add(file));
214
+ }
215
+ const watchedFiles = [...files].sort();
216
+ if (this._testWatcher && JSON.stringify(this._testWatcher.watchedFiles) === JSON.stringify(watchedFiles)) return;
217
+ if (this._testWatcher) {
218
+ if (this._testWatcher.collector.size) this._dispatchEvent({
219
+ method: 'filesChanged',
220
+ params: {
221
+ fileNames: [...this._testWatcher.collector]
222
+ }
223
+ });
224
+ clearTimeout(this._testWatcher.timer);
225
+ this._testWatcher.watcher.close().then(() => {});
226
+ this._testWatcher = undefined;
227
+ }
228
+ if (!watchedFiles.length) return;
229
+ const collector = new Set();
230
+ const watcher = _utilsBundle.chokidar.watch(watchedFiles, {
231
+ ignoreInitial: true
232
+ }).on('all', async (event, file) => {
233
+ if (event !== 'add' && event !== 'change') return;
234
+ (0, _compilationCache.collectAffectedTestFiles)(file, collector);
235
+ if (this._testWatcher.timer) clearTimeout(this._testWatcher.timer);
236
+ this._testWatcher.timer = setTimeout(() => {
237
+ const fileNames = [...collector];
238
+ collector.clear();
239
+ this._dispatchEvent({
240
+ method: 'filesChanged',
241
+ params: {
242
+ fileNames
243
+ }
244
+ });
245
+ }, 250);
246
+ });
247
+ this._testWatcher = {
248
+ watcher,
249
+ watchedFiles,
250
+ collector
251
+ };
252
+ }
253
+ async _stopTests() {
254
+ var _this$_testRun, _this$_testRun$stop, _this$_testRun2;
255
+ (_this$_testRun = this._testRun) === null || _this$_testRun === void 0 ? void 0 : (_this$_testRun$stop = _this$_testRun.stop) === null || _this$_testRun$stop === void 0 ? void 0 : _this$_testRun$stop.resolve();
256
+ await ((_this$_testRun2 = this._testRun) === null || _this$_testRun2 === void 0 ? void 0 : _this$_testRun2.run);
257
+ }
258
+ }
259
+ const dispatchFuncSource = String(message => {
260
+ window.dispatch(message);
261
+ });
262
+ async function runUIMode(config) {
263
+ var _uiMode$globalCleanup;
264
+ const uiMode = new UIMode(config);
265
+ const status = await uiMode.runGlobalSetup();
266
+ if (status !== 'passed') return status;
267
+ await uiMode.showUI();
268
+ return (await ((_uiMode$globalCleanup = uiMode.globalCleanup) === null || _uiMode$globalCleanup === void 0 ? void 0 : _uiMode$globalCleanup.call(uiMode))) || 'passed';
269
+ }
270
+ function chunkToPayload(type, chunk) {
271
+ if (chunk instanceof Buffer) return {
272
+ type,
273
+ buffer: chunk.toString('base64')
274
+ };
275
+ return {
276
+ type,
277
+ text: chunk
278
+ };
279
+ }
@@ -23,9 +23,13 @@ var _processHost = require("./processHost");
23
23
 
24
24
  let lastWorkerIndex = 0;
25
25
  class WorkerHost extends _processHost.ProcessHost {
26
- constructor(testGroup, parallelIndex, config) {
26
+ constructor(testGroup, parallelIndex, config, extraEnv) {
27
27
  const workerIndex = lastWorkerIndex++;
28
- super(require.resolve('../worker/workerMain.js'), `worker-${workerIndex}`);
28
+ super(require.resolve('../worker/workerMain.js'), `worker-${workerIndex}`, {
29
+ ...extraEnv,
30
+ FORCE_COLOR: '1',
31
+ DEBUG_COLORS: '1'
32
+ });
29
33
  this.parallelIndex = void 0;
30
34
  this.workerIndex = void 0;
31
35
  this._hash = void 0;
@@ -43,10 +47,7 @@ class WorkerHost extends _processHost.ProcessHost {
43
47
  };
44
48
  }
45
49
  async start() {
46
- await this.startRunner(this._params, false, {
47
- FORCE_COLOR: '1',
48
- DEBUG_COLORS: '1'
49
- });
50
+ await this.startRunner(this._params, false);
50
51
  }
51
52
  runTestGroup(runPayload) {
52
53
  this.sendMessageNoReply({