flashwright 1.64.1-flashwright.1 → 1.64.1-flashwright.3

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/README.md CHANGED
@@ -13,4 +13,6 @@ npx playwright install chromium
13
13
 
14
14
  Without the test runner, `playwright` is `flashwright` and `playwright-core` is `flashwright-core`. See the [project page](https://github.com/xcodebeast/flashwright) for benchmarks, speed options and the differences from Playwright.
15
15
 
16
+ Re-running tests, like an agent checking its work? Outside CI, a warm session keeps the browser between runs, so one test re-runs in about 0.1 s instead of 0.7 s with Playwright ([warm session](https://github.com/xcodebeast/flashwright#warm-session); `FLASHWRIGHT_SESSION=0` turns it off).
17
+
16
18
  Flashwright is an independent fork and is not affiliated with Microsoft. Apache-2.0, like Playwright.
package/cli.js CHANGED
@@ -24,16 +24,14 @@ if (nodeModule.enableCompileCache && !process.env.NODE_DISABLE_COMPILE_CACHE) {
24
24
  process.env.NODE_COMPILE_CACHE = directory;
25
25
  }
26
26
 
27
- // Flashwright: compile Playwright's bundles with code caches that include their lazily compiled
28
- // functions (see codeCache.ts).
29
- require('./lib/codeCache').installCodeCache(process.argv[2] === 'test' ? 'runner' : 'cli');
30
-
31
- // Flashwright: start the first test worker while the CLI loads.
32
- require('./lib/runner/workerStandby').prespawnWorkerForTestCommand(process.argv);
33
- // Flashwright: `cli` commands only forward to a browser session; skip loading every command.
34
- if (process.argv[2] === 'cli') {
35
- require('playwright-core/lib/coreBundle').runCliClient();
36
- } else {
37
- const { program } = require('./lib/program');
38
- program.parse(process.argv);
39
- }
27
+ // Flashwright: runs the command here, or in a runner process that the warm session prepared
28
+ // ahead of time (see session.ts). `cli` commands only forward to a browser session.
29
+ require('./lib/runner/session').runCli(process.argv, {
30
+ // Compiles Playwright's bundles with code caches that include their lazily compiled functions.
31
+ installCodeCache: role => require('./lib/codeCache').installCodeCache(role),
32
+ // Starts the first test workers while the CLI loads.
33
+ prespawnWorkers: argv => require('./lib/runner/workerStandby').prespawnWorkerForTestCommand(argv),
34
+ retargetWorkers: argv => require('./lib/runner/workerStandby').retargetStandbys(argv),
35
+ loadProgram: () => require('./lib/program').program,
36
+ runCliClient: () => require('playwright-core/lib/coreBundle').runCliClient(),
37
+ });
@@ -37,6 +37,7 @@ var import_fs = __toESM(require("fs"));
37
37
  var import_path = __toESM(require("path"));
38
38
  var import_common = require("../common");
39
39
  var import_runner = require("../runner");
40
+ var import_session = require("../runner/session");
40
41
  const { gracefullyProcessExitDoNotHang } = require("playwright-core/lib/coreBundle").utils;
41
42
  async function runTests(args, opts) {
42
43
  const cliOverrides = overridesFromOptions(opts);
@@ -90,7 +91,7 @@ async function runTests(args, opts) {
90
91
  }
91
92
  const status = await import_runner.testRunner.runAllTestsWithConfig(config, options);
92
93
  const exitCode = status === "interrupted" ? 130 : status === "passed" ? 0 : 1;
93
- gracefullyProcessExitDoNotHang(exitCode);
94
+ gracefullyProcessExitDoNotHang(exitCode, () => (0, import_session.flushSessionBrowsers)(exitCode));
94
95
  }
95
96
  async function runTestServerAction(opts) {
96
97
  const host = opts.host;
package/lib/codeCache.js CHANGED
@@ -41,7 +41,14 @@ var import_path = __toESM(require("path"));
41
41
  var import_vm = __toESM(require("vm"));
42
42
  var minimumSize = 32 * 1024;
43
43
  var pending = [];
44
+ var loaded = [];
44
45
  var installed = false;
46
+ var ranTests = false;
47
+ var refreshAtExit = false;
48
+ globalThis[/* @__PURE__ */ Symbol.for("flashwright.codeCache")] = {
49
+ ranTests: () => ranTests = true,
50
+ refreshAtExit: () => refreshAtExit = true
51
+ };
45
52
  function installCodeCache(role) {
46
53
  if (installed || process.env.NODE_DISABLE_COMPILE_CACHE || process.env.FLASHWRIGHT_DISABLE_CODE_CACHE || process.env.NODE_V8_COVERAGE)
47
54
  return;
@@ -50,6 +57,7 @@ function installCodeCache(role) {
50
57
  if (!importModuleDynamically || typeof originalCompile !== "function")
51
58
  return;
52
59
  installed = true;
60
+ ranTests = ranTests || role === "cli";
53
61
  silenceDefaultLoaderWarning(importModuleDynamically);
54
62
  const roots = packageLibDirs();
55
63
  const cacheDir = import_path.default.join(import_os.default.tmpdir(), "flashwright-code-cache", `${process.version}-${process.arch}`, role);
@@ -101,6 +109,8 @@ function compileWithCache(content, filename, cacheDir, importModuleDynamically)
101
109
  const script = new import_vm.default.Script(import_module.default.wrap(content), { filename, cachedData, importModuleDynamically });
102
110
  if (!cachedData || script.cachedDataRejected)
103
111
  pending.push({ script, cacheFile, staleFiles: staleCacheFiles(cacheDir, fileKey, cacheFile) });
112
+ else
113
+ loaded.push({ script, cacheFile, size: cachedData.length });
104
114
  return script.runInThisContext({ displayErrors: true });
105
115
  }
106
116
  function staleCacheFiles(cacheDir, fileKey, cacheFile) {
@@ -121,16 +131,27 @@ function makeRequireFunction(mod) {
121
131
  return require2;
122
132
  }
123
133
  function writeCodeCaches() {
124
- for (const { script, cacheFile, staleFiles } of pending.splice(0)) {
125
- try {
126
- import_fs.default.mkdirSync(import_path.default.dirname(cacheFile), { recursive: true });
127
- const temporary = `${cacheFile}.${process.pid}`;
128
- import_fs.default.writeFileSync(temporary, script.createCachedData());
129
- import_fs.default.renameSync(temporary, cacheFile);
130
- for (const file of staleFiles)
131
- import_fs.default.rmSync(file, { force: true });
132
- } catch {
133
- }
134
+ if (!ranTests)
135
+ return;
136
+ for (const { script, cacheFile, staleFiles } of pending.splice(0))
137
+ writeCodeCache(cacheFile, script.createCachedData(), staleFiles);
138
+ if (!refreshAtExit)
139
+ return;
140
+ for (const { script, cacheFile, size } of loaded.splice(0)) {
141
+ const data = script.createCachedData();
142
+ if (data.length > size * 1.1)
143
+ writeCodeCache(cacheFile, data, []);
144
+ }
145
+ }
146
+ function writeCodeCache(cacheFile, data, staleFiles) {
147
+ try {
148
+ import_fs.default.mkdirSync(import_path.default.dirname(cacheFile), { recursive: true });
149
+ const temporary = `${cacheFile}.${process.pid}`;
150
+ import_fs.default.writeFileSync(temporary, data);
151
+ import_fs.default.renameSync(temporary, cacheFile);
152
+ for (const file of staleFiles)
153
+ import_fs.default.rmSync(file, { force: true });
154
+ } catch {
134
155
  }
135
156
  }
136
157
  if (/workerProcessEntry\.js$/.test(process.argv[1] || ""))
@@ -1,8 +1,8 @@
1
1
  # packages/playwright/lib/codeCache.js
2
- # total: 6.4 KB
2
+ # total: 7.0 KB
3
3
 
4
4
  ## Inlined (1)
5
- 4.9 KB packages/playwright/src/codeCache.ts
5
+ 5.5 KB packages/playwright/src/codeCache.ts
6
6
 
7
7
  ## External (1)
8
8
  playwright-core/package.json
@@ -40,6 +40,7 @@ __export(index_exports, {
40
40
  fixtures: () => fixtures_exports,
41
41
  ipc: () => ipc_exports,
42
42
  mergeTests: () => mergeTests,
43
+ originalProcessExit: () => originalProcessExit,
43
44
  poolBuilder: () => poolBuilder_exports,
44
45
  processRunner: () => process_exports,
45
46
  startProcessRunner: () => startProcessRunner,
@@ -1920,6 +1921,7 @@ var PoolBuilder = class _PoolBuilder {
1920
1921
  var process_exports = {};
1921
1922
  __export(process_exports, {
1922
1923
  ProcessRunner: () => ProcessRunner,
1924
+ originalProcessExit: () => originalProcessExit,
1923
1925
  startProcessRunner: () => startProcessRunner
1924
1926
  });
1925
1927
  var import_bootstrap = require("playwright-core/lib/bootstrap");
@@ -1930,6 +1932,10 @@ var { setBoxedStackPrefixes } = require("playwright-core/lib/coreBundle").utils;
1930
1932
  var ProcessRunner = class {
1931
1933
  async gracefullyClose() {
1932
1934
  }
1935
+ // Flashwright: see WorkerMain.canDetachTeardown.
1936
+ canDetachTeardown() {
1937
+ return false;
1938
+ }
1933
1939
  dispatchEvent(method, params) {
1934
1940
  const response = { method, params };
1935
1941
  sendMessageToParent({ method: "__dispatch__", params: response });
@@ -1946,6 +1952,7 @@ var gracefullyCloseCalled = false;
1946
1952
  var forceExitInitiated = false;
1947
1953
  var processRunner;
1948
1954
  var startingEnv = { ...process.env };
1955
+ var originalProcessExit = process.exit;
1949
1956
  setBoxedStackPrefixes([import_package4.packageRoot]);
1950
1957
  function startProcessRunner(create) {
1951
1958
  sendMessageToParent({ method: "ready" });
@@ -1969,6 +1976,10 @@ function startProcessRunner(create) {
1969
1976
  const keys = /* @__PURE__ */ new Set([...Object.keys(process.env), ...Object.keys(startingEnv)]);
1970
1977
  const producedEnv = [...keys].filter((key) => startingEnv[key] !== process.env[key]).map((key) => [key, process.env[key] ?? null]);
1971
1978
  sendMessageToParent({ method: "__env_produced__", params: producedEnv });
1979
+ if (processRunner?.canDetachTeardown()) {
1980
+ sendMessageToParent({ method: "__teardown_detached__" });
1981
+ globalThis[/* @__PURE__ */ Symbol.for("flashwright.codeCache")]?.refreshAtExit();
1982
+ }
1972
1983
  await gracefullyCloseAndExit(false);
1973
1984
  return;
1974
1985
  }
@@ -2963,6 +2974,7 @@ function serializeLoadError(file2, error) {
2963
2974
  fixtures,
2964
2975
  ipc,
2965
2976
  mergeTests,
2977
+ originalProcessExit,
2966
2978
  poolBuilder,
2967
2979
  processRunner,
2968
2980
  startProcessRunner,
@@ -1,5 +1,5 @@
1
1
  # packages/playwright/lib/common/index.js
2
- # total: 115.2 KB
2
+ # total: 115.6 KB
3
3
 
4
4
  ## Inlined (20)
5
5
  12.6 KB packages/playwright/src/common/config.ts
@@ -8,7 +8,7 @@
8
8
  0.8 KB packages/playwright/src/common/index.ts
9
9
  1.3 KB packages/playwright/src/common/ipc.ts
10
10
  2.1 KB packages/playwright/src/common/poolBuilder.ts
11
- 4.4 KB packages/playwright/src/common/process.ts
11
+ 4.8 KB packages/playwright/src/common/process.ts
12
12
  4.9 KB packages/playwright/src/common/suiteUtils.ts
13
13
  8.7 KB packages/playwright/src/common/test.ts
14
14
  2.0 KB packages/playwright/src/common/testLoader.ts
package/lib/index.js CHANGED
@@ -213,6 +213,7 @@ const playwrightFixtures = {
213
213
  playwright._defaultLaunchOptions = options;
214
214
  await use(options);
215
215
  playwright._defaultLaunchOptions = void 0;
216
+ await (0, import_speculativeBrowser.returnSpeculativeBrowser)();
216
217
  }, { scope: "worker", auto: true, box: true }],
217
218
  browser: [async ({ playwright, browserName, _browserOptions, connectOptions, _recycleContext }, use, workerInfo) => {
218
219
  if (!["chromium", "firefox", "webkit"].includes(browserName))
@@ -239,6 +240,8 @@ const playwrightFixtures = {
239
240
  if (process.env.PLAYWRIGHT_DASHBOARD)
240
241
  await browser.bind(`worker-${workerInfo.parallelIndex}`);
241
242
  await use(browser);
243
+ if (await (0, import_speculativeBrowser.handBrowsersToSession)(browser, true))
244
+ return;
242
245
  if (browser.contexts().length)
243
246
  await browser.close({ reason: "Test ended." });
244
247
  else
@@ -13160,7 +13160,7 @@ function indent2(snapshot, indent3) {
13160
13160
  }
13161
13161
 
13162
13162
  // packages/playwright/src/matchers/expect.ts
13163
- var { parseStackFrame, captureRawStack } = require("playwright-core/lib/coreBundle").utils;
13163
+ var { captureFilteredStackTrace, captureRawStack, filteredStackTrace, parseStackFrame } = require("playwright-core/lib/coreBundle").utils;
13164
13164
  var { escapeWithQuotes, isString: isString4 } = require("playwright-core/lib/coreBundle").iso;
13165
13165
  var { pollAgainstDeadline: pollAgainstDeadline2 } = require("playwright-core/lib/coreBundle").iso;
13166
13166
  var { currentZone } = require("playwright-core/lib/coreBundle").utils;
@@ -13313,7 +13313,8 @@ function callMatcherAsStep(matcherName, info, actual, matcher, args, promise) {
13313
13313
  const suffixes = computeMatcherTitleSuffix(matcherName, actual, args);
13314
13314
  const defaultTitle = `${info.poll ? "poll " : ""}${info.isSoft ? "soft " : ""}${info.isNot ? "not " : ""}${matcherName}${suffixes.titleSuffix || ""}`;
13315
13315
  const title = customMessage || `Expect ${escapeWithQuotes(defaultTitle, '"')}`;
13316
- const stackFrames = expectConfig().filteredStackTrace(captureRawStack());
13316
+ const filter = expectConfig().filteredStackTrace;
13317
+ const stackFrames = filter === filteredStackTrace ? captureFilteredStackTrace() : filter(captureRawStack());
13317
13318
  const params = { ...suffixes.params };
13318
13319
  if (args[0])
13319
13320
  params.expected = args[0];
@@ -1,5 +1,5 @@
1
1
  # packages/playwright/lib/matchers/expect.js
2
- # total: 534.4 KB
2
+ # total: 534.5 KB
3
3
 
4
4
  ## Inlined (59)
5
5
  7.9 KB node_modules/@babel/code-frame/lib/index.js
@@ -51,7 +51,7 @@
51
51
  7.6 KB node_modules/stack-utils/index.js
52
52
  0.4 KB node_modules/stack-utils/node_modules/escape-string-regexp/index.js
53
53
  3.1 KB node_modules/supports-color/index.js
54
- 10.3 KB packages/playwright/src/matchers/expect.ts
54
+ 10.4 KB packages/playwright/src/matchers/expect.ts
55
55
  45.3 KB packages/playwright/src/matchers/expectLibrary.ts
56
56
  3.3 KB packages/playwright/src/matchers/matcherHint.ts
57
57
  17.4 KB packages/playwright/src/matchers/matchers.ts
@@ -1896,10 +1896,12 @@ var import_fs3 = __toESM(require("fs"));
1896
1896
  var import_child_process = __toESM(require("child_process"));
1897
1897
  var import_events = require("events");
1898
1898
  var import_workerStandby = require("./workerStandby");
1899
+ var import_session = require("./session");
1899
1900
  var debug3 = require("playwright-core/lib/utilsBundle").debug;
1900
1901
  var { assert } = require("playwright-core/lib/coreBundle").iso;
1901
1902
  var { monotonicTime: monotonicTime3, timeOrigin } = require("playwright-core/lib/coreBundle").iso;
1902
1903
  var { raceAgainstDeadline: raceAgainstDeadline2 } = require("playwright-core/lib/coreBundle").iso;
1904
+ var { ManualPromise: ManualPromise2 } = require("playwright-core/lib/coreBundle").iso;
1903
1905
  var { killProcessTree } = require("playwright-core/lib/coreBundle").utils;
1904
1906
  var ProcessHost = class extends import_events.EventEmitter {
1905
1907
  constructor(entryScript, processName, env) {
@@ -1911,6 +1913,8 @@ var ProcessHost = class extends import_events.EventEmitter {
1911
1913
  this._callbacks = /* @__PURE__ */ new Map();
1912
1914
  this._producedEnv = {};
1913
1915
  this._requestHandlers = /* @__PURE__ */ new Map();
1916
+ // Flashwright: resolved when a stopping worker says that it can finish on its own (see stop).
1917
+ this._teardownDetached = new ManualPromise2();
1914
1918
  this._entryScript = entryScript;
1915
1919
  this._processName = processName;
1916
1920
  this._extraEnv = env;
@@ -1944,10 +1948,15 @@ var ProcessHost = class extends import_events.EventEmitter {
1944
1948
  });
1945
1949
  this.process.on("error", (e) => {
1946
1950
  });
1947
- this.process.on("message", (message) => {
1951
+ (0, import_session.trackSessionWorker)(this.process);
1952
+ this.process.on("message", (message, handle) => {
1953
+ if ((0, import_session.receiveWorkerMessage)(this.process, message, handle))
1954
+ return;
1948
1955
  if (debug3.enabled("pw:test:protocol"))
1949
1956
  debug3("pw:test:protocol")("\u25C0 RECV " + JSON.stringify(message));
1950
- if (message.method === "__env_produced__") {
1957
+ if (message.method === "__teardown_detached__") {
1958
+ this._teardownDetached.resolve(true);
1959
+ } else if (message.method === "__env_produced__") {
1951
1960
  const producedEnv = message.params;
1952
1961
  this._producedEnv = Object.fromEntries(producedEnv.map((e) => [e[0], e[1] ?? void 0]));
1953
1962
  } else if (message.method === "__dispatch__") {
@@ -2024,14 +2033,18 @@ var ProcessHost = class extends import_events.EventEmitter {
2024
2033
  onRequest(method, handler) {
2025
2034
  this._requestHandlers.set(method, handler);
2026
2035
  }
2027
- async stop() {
2036
+ // Flashwright: with `detachTeardown`, also returns once the process says that what it has left to
2037
+ // do cannot change the run's outcome (see WorkerMain.canDetachTeardown); the warm session's
2038
+ // runner waits for it to exit before it exits itself.
2039
+ async stop(options = {}) {
2028
2040
  if (!this._processDidExit && !this._didSendStop) {
2029
2041
  this.send({ method: "__stop__" });
2030
2042
  this._didSendStop = true;
2031
2043
  }
2032
2044
  if (this._didExitAndRanOnExit)
2033
2045
  return;
2034
- const exitPromise = new Promise((f) => this.once("exit", () => f()));
2046
+ const exited = new Promise((f) => this.once("exit", () => f(false)));
2047
+ const exitPromise = options.detachTeardown ? Promise.race([exited, this._teardownDetached]) : exited;
2035
2048
  const timeout = +(process.env.PWTEST_CHILD_PROCESS_TIMEOUT || 5 * 60 * 1e3);
2036
2049
  let lastHeartbeat = monotonicTime3();
2037
2050
  const onHeartbeat = () => lastHeartbeat = monotonicTime3();
@@ -2039,8 +2052,11 @@ var ProcessHost = class extends import_events.EventEmitter {
2039
2052
  try {
2040
2053
  while (true) {
2041
2054
  const result = await raceAgainstDeadline2(() => exitPromise, lastHeartbeat + timeout);
2042
- if (!result.timedOut)
2055
+ if (!result.timedOut) {
2056
+ if (result.result)
2057
+ (0, import_session.trackDetachedTeardown)(exited);
2043
2058
  return;
2059
+ }
2044
2060
  if (monotonicTime3() < lastHeartbeat + timeout)
2045
2061
  continue;
2046
2062
  this.emit("processError", { message: `Error: ${this._processName} process did not exit within ${timeout}ms after stop, force-killed it` });
@@ -3088,7 +3104,7 @@ var TeleReporterEmitter = class {
3088
3104
  // packages/playwright/src/reporters/blob.ts
3089
3105
  var mime = require("playwright-core/lib/utilsBundle").mime;
3090
3106
  var yazl = require("playwright-core/lib/utilsBundle").yazl;
3091
- var { ManualPromise: ManualPromise2 } = require("playwright-core/lib/coreBundle").iso;
3107
+ var { ManualPromise: ManualPromise3 } = require("playwright-core/lib/coreBundle").iso;
3092
3108
  var { calculateSha1: calculateSha12, createGuid: createGuid2 } = require("playwright-core/lib/coreBundle").utils;
3093
3109
  var { removeFolders, sanitizeForFilePath } = require("playwright-core/lib/coreBundle").utils;
3094
3110
  var currentBlobReportVersion = 2;
@@ -3124,7 +3140,7 @@ var BlobReporter = class extends TeleReporterEmitter {
3124
3140
  await super.onEnd(result);
3125
3141
  const zipFileName = await this._prepareOutputFile();
3126
3142
  const zipFile = new yazl.ZipFile();
3127
- const zipFinishPromise = new ManualPromise2();
3143
+ const zipFinishPromise = new ManualPromise3();
3128
3144
  const finishPromise = zipFinishPromise.catch((e) => {
3129
3145
  throw new Error(`Failed to write report ${zipFileName}: ` + e.message);
3130
3146
  });
@@ -5673,10 +5689,10 @@ var WorkerHost = class extends ProcessHost {
5673
5689
  async onExit() {
5674
5690
  await removeFolders3([this._params.artifactsDir]);
5675
5691
  }
5676
- async stop(didFail) {
5677
- if (didFail)
5692
+ async stop(options = {}) {
5693
+ if (options.didFail)
5678
5694
  this._didFail = true;
5679
- await super.stop();
5695
+ await super.stop(options);
5680
5696
  }
5681
5697
  runTestGroup(runPayload) {
5682
5698
  this.sendMessageNoReply({ method: "runTestGroup", params: runPayload });
@@ -5703,7 +5719,7 @@ var import_workerStandby2 = require("./workerStandby");
5703
5719
  var import_common7 = require("../common");
5704
5720
  var import_util13 = require("../util");
5705
5721
  var colors4 = require("playwright-core/lib/utilsBundle").colors;
5706
- var { ManualPromise: ManualPromise3 } = require("playwright-core/lib/coreBundle").iso;
5722
+ var { ManualPromise: ManualPromise4 } = require("playwright-core/lib/coreBundle").iso;
5707
5723
  var { eventsHelper } = require("playwright-core/lib/coreBundle").utils;
5708
5724
  var Dispatcher = class {
5709
5725
  constructor(testRun, options = {}) {
@@ -5713,7 +5729,7 @@ var Dispatcher = class {
5713
5729
  this._isolatedJobs = /* @__PURE__ */ new Set();
5714
5730
  this._workerLimitPerProjectId = /* @__PURE__ */ new Map();
5715
5731
  this._queuedOrRunningHashCount = /* @__PURE__ */ new Map();
5716
- this._finished = new ManualPromise3();
5732
+ this._finished = new ManualPromise4();
5717
5733
  this._isStopped = true;
5718
5734
  this._extraEnvByProjectId = /* @__PURE__ */ new Map();
5719
5735
  this._producedEnvByProjectId = /* @__PURE__ */ new Map();
@@ -5804,10 +5820,7 @@ var Dispatcher = class {
5804
5820
  const result = await jobDispatcher.jobResult;
5805
5821
  this._updateCounterForWorkerHash(job.workerHash, -1);
5806
5822
  if (result.didFail) {
5807
- void worker.stop(
5808
- true
5809
- /* didFail */
5810
- );
5823
+ void worker.stop({ didFail: true });
5811
5824
  (0, import_workerStandby2.recordWorkerRestart)(!!result.remainingJob || !!this._queue.length);
5812
5825
  } else if (this._isWorkerRedundant(worker)) {
5813
5826
  void worker.stop();
@@ -5914,17 +5927,17 @@ var Dispatcher = class {
5914
5927
  producedEnvByProjectId() {
5915
5928
  return this._producedEnvByProjectId;
5916
5929
  }
5917
- async stop() {
5930
+ async stop(options) {
5918
5931
  if (this._isStopped)
5919
5932
  return;
5920
5933
  this._isStopped = true;
5921
- await Promise.all(this._workerSlots.map(({ worker }) => worker?.stop()));
5934
+ await Promise.all(this._workerSlots.map(({ worker }) => worker?.stop(options)));
5922
5935
  this._checkFinished();
5923
5936
  }
5924
5937
  };
5925
5938
  var JobDispatcher = class {
5926
5939
  constructor(job, testRun, onMaxFailuresReached) {
5927
- this.jobResult = new ManualPromise3();
5940
+ this.jobResult = new ManualPromise4();
5928
5941
  this._listeners = [];
5929
5942
  this._failedTests = /* @__PURE__ */ new Set();
5930
5943
  this._failedWithNonRetriableError = /* @__PURE__ */ new Set();
@@ -6241,6 +6254,7 @@ function chunkFromParams(params) {
6241
6254
 
6242
6255
  // packages/playwright/src/runner/tasks.ts
6243
6256
  var import_workerStandby3 = require("./workerStandby");
6257
+ var import_session2 = require("./session");
6244
6258
 
6245
6259
  // packages/playwright/src/runner/sigIntWatcher.ts
6246
6260
  var SigIntWatcher = class {
@@ -6317,7 +6331,7 @@ var FixedNodeSIGINTHandler = class {
6317
6331
  var import_util14 = require("../util");
6318
6332
  var colors5 = require("playwright-core/lib/utilsBundle").colors;
6319
6333
  var debug4 = require("playwright-core/lib/utilsBundle").debug;
6320
- var { ManualPromise: ManualPromise4 } = require("playwright-core/lib/coreBundle").iso;
6334
+ var { ManualPromise: ManualPromise5 } = require("playwright-core/lib/coreBundle").iso;
6321
6335
  var { monotonicTime: monotonicTime4 } = require("playwright-core/lib/coreBundle").iso;
6322
6336
  var TaskRunner = class _TaskRunner {
6323
6337
  constructor(reporter, globalTimeoutForError) {
@@ -6336,7 +6350,7 @@ var TaskRunner = class _TaskRunner {
6336
6350
  const teardownStatus = await cleanup();
6337
6351
  return status === "passed" ? teardownStatus : status;
6338
6352
  }
6339
- async runDeferCleanup(context, deadline, cancelPromise = new ManualPromise4()) {
6353
+ async runDeferCleanup(context, deadline, cancelPromise = new ManualPromise5()) {
6340
6354
  const sigintWatcher = new SigIntWatcher();
6341
6355
  const timeoutWatcher = new TimeoutWatcher(deadline);
6342
6356
  const teardownRunner = new _TaskRunner(this._reporter, this._globalTimeoutForError);
@@ -6394,7 +6408,7 @@ var TaskRunner = class _TaskRunner {
6394
6408
  var TimeoutWatcher = class {
6395
6409
  constructor(deadline) {
6396
6410
  this._timedOut = false;
6397
- this.promise = new ManualPromise4();
6411
+ this.promise = new ManualPromise5();
6398
6412
  if (!deadline)
6399
6413
  return;
6400
6414
  if (deadline - monotonicTime4() <= 0) {
@@ -6518,7 +6532,7 @@ function orderTestGroupsByDuration(testGroups, durations) {
6518
6532
  // packages/playwright/src/runner/tasks.ts
6519
6533
  var import_util16 = require("../util");
6520
6534
  var debug5 = require("playwright-core/lib/utilsBundle").debug;
6521
- var { ManualPromise: ManualPromise5 } = require("playwright-core/lib/coreBundle").iso;
6535
+ var { ManualPromise: ManualPromise6 } = require("playwright-core/lib/coreBundle").iso;
6522
6536
  var { monotonicTime: monotonicTime5 } = require("playwright-core/lib/coreBundle").iso;
6523
6537
  var { removeFolders: removeFolders4 } = require("playwright-core/lib/coreBundle").utils;
6524
6538
  var readDirAsync2 = (0, import_util15.promisify)(import_fs14.default.readdir);
@@ -6854,7 +6868,8 @@ function createRunTestsTask() {
6854
6868
  orderTestGroupsByDuration(phaseTestGroups, durations);
6855
6869
  if (phaseTestGroups.length) {
6856
6870
  await dispatcher.run(phaseTestGroups, extraEnvByProjectId);
6857
- await dispatcher.stop();
6871
+ globalThis[/* @__PURE__ */ Symbol.for("flashwright.codeCache")]?.ranTests();
6872
+ await dispatcher.stop({ detachTeardown: !nextPhase && (0, import_session2.isWarmSessionRun)() });
6858
6873
  for (const [projectId, envProduced] of dispatcher.producedEnvByProjectId()) {
6859
6874
  const extraEnv = extraEnvByProjectId.get(projectId) || {};
6860
6875
  extraEnvByProjectId.set(projectId, { ...extraEnv, ...envProduced });
@@ -6932,7 +6947,7 @@ var LastRunReporter = class {
6932
6947
  };
6933
6948
 
6934
6949
  // packages/playwright/src/runner/testRunner.ts
6935
- var { ManualPromise: ManualPromise6 } = require("playwright-core/lib/coreBundle").iso;
6950
+ var { ManualPromise: ManualPromise7 } = require("playwright-core/lib/coreBundle").iso;
6936
6951
  var { setPlaywrightTestProcessEnv } = require("playwright-core/lib/coreBundle").utils;
6937
6952
  var { gracefullyProcessExitDoNotHang: gracefullyProcessExitDoNotHang2 } = require("playwright-core/lib/coreBundle").utils;
6938
6953
  var TestRunnerEvent = {
@@ -7135,7 +7150,7 @@ var TestRunner = class extends import_events3.default {
7135
7150
  };
7136
7151
  const configReporters = params.disableConfigReporters ? [] : await createReporters(config2, "test", void 0, options);
7137
7152
  const reporter = new InternalReporter([...configReporters, userReporter]);
7138
- const stop = new ManualPromise6();
7153
+ const stop = new ManualPromise7();
7139
7154
  const testRun = new TestRun(config2, reporter, options);
7140
7155
  if (params.testIds) {
7141
7156
  const testIdSet = new Set(params.testIds);
@@ -7269,7 +7284,7 @@ var uiModeReporter_default = UIModeReporter;
7269
7284
  // packages/playwright/src/runner/testServer.ts
7270
7285
  var debug6 = require("playwright-core/lib/utilsBundle").debug;
7271
7286
  var open2 = require("playwright-core/lib/utilsBundle").open;
7272
- var { ManualPromise: ManualPromise7 } = require("playwright-core/lib/coreBundle").iso;
7287
+ var { ManualPromise: ManualPromise8 } = require("playwright-core/lib/coreBundle").iso;
7273
7288
  var { isUnderTest } = require("playwright-core/lib/coreBundle").utils;
7274
7289
  var { HttpServer: HttpServer2 } = require("playwright-core/lib/coreBundle").utils;
7275
7290
  var { gracefullyProcessExitDoNotHang: gracefullyProcessExitDoNotHang3 } = require("playwright-core/lib/coreBundle").utils;
@@ -7476,7 +7491,7 @@ async function runTestServer(configFile, configCLIOverrides, options) {
7476
7491
  }
7477
7492
  async function innerRunTestServer(configLocation, configCLIOverrides, options, openUI) {
7478
7493
  const testServer = new TestServer(configLocation, configCLIOverrides);
7479
- const cancelPromise = new ManualPromise7();
7494
+ const cancelPromise = new ManualPromise8();
7480
7495
  const sigintWatcher = new SigIntWatcher();
7481
7496
  process.stdin.on("close", () => gracefullyProcessExitDoNotHang3(0));
7482
7497
  void sigintWatcher.promise().then(() => cancelPromise.resolve());
@@ -7852,7 +7867,7 @@ var TestServerConnection = class {
7852
7867
  // packages/playwright/src/runner/watchMode.ts
7853
7868
  var colors6 = require("playwright-core/lib/utilsBundle").colors;
7854
7869
  var enquirer = require("playwright-core/lib/utilsBundle").enquirer;
7855
- var { ManualPromise: ManualPromise8 } = require("playwright-core/lib/coreBundle").iso;
7870
+ var { ManualPromise: ManualPromise9 } = require("playwright-core/lib/coreBundle").iso;
7856
7871
  var { createGuid: createGuid3 } = require("playwright-core/lib/coreBundle").utils;
7857
7872
  var { getPackageManagerExecCommand: getPackageManagerExecCommand3 } = require("playwright-core/lib/coreBundle").utils;
7858
7873
  var { eventsHelper: eventsHelper2 } = require("playwright-core/lib/coreBundle").utils;
@@ -7903,7 +7918,7 @@ async function runWatchModeLoop(configLocation, initialOptions) {
7903
7918
  } });
7904
7919
  const dirtyTestFiles = /* @__PURE__ */ new Set();
7905
7920
  const dirtyTestIds = /* @__PURE__ */ new Set();
7906
- let onDirtyTests = new ManualPromise8();
7921
+ let onDirtyTests = new ManualPromise9();
7907
7922
  let queue = Promise.resolve();
7908
7923
  const changedFiles = /* @__PURE__ */ new Set();
7909
7924
  testServerConnection.onTestFilesChanged(({ testFiles }) => {
@@ -7922,7 +7937,7 @@ async function runWatchModeLoop(configLocation, initialOptions) {
7922
7937
  changedFiles.clear();
7923
7938
  if (dirtyTestIds.size > 0) {
7924
7939
  onDirtyTests.resolve("changed");
7925
- onDirtyTests = new ManualPromise8();
7940
+ onDirtyTests = new ManualPromise9();
7926
7941
  }
7927
7942
  });
7928
7943
  });
@@ -8049,7 +8064,7 @@ async function runWatchModeLoop(configLocation, initialOptions) {
8049
8064
  return result === "passed" ? teardown.status : result;
8050
8065
  }
8051
8066
  function readKeyPress(handler) {
8052
- const promise = new ManualPromise8();
8067
+ const promise = new ManualPromise9();
8053
8068
  const rl = import_readline.default.createInterface({ input: process.stdin, escapeCodeTimeout: 50 });
8054
8069
  import_readline.default.emitKeypressEvents(process.stdin, rl);
8055
8070
  if (process.stdin.isTTY)
@@ -1,5 +1,5 @@
1
1
  # packages/playwright/lib/runner/index.js
2
- # total: 321.2 KB
2
+ # total: 322.4 KB
3
3
 
4
4
  ## Inlined (49)
5
5
  1.3 KB packages/playwright/src/isomorphic/events.ts
@@ -35,14 +35,14 @@
35
35
  1.7 KB packages/playwright/src/runner/lastRun.ts
36
36
  1.6 KB packages/playwright/src/runner/loaderHost.ts
37
37
  13.3 KB packages/playwright/src/runner/loadUtils.ts
38
- 6.3 KB packages/playwright/src/runner/processHost.ts
38
+ 7.3 KB packages/playwright/src/runner/processHost.ts
39
39
  7.9 KB packages/playwright/src/runner/projectUtils.ts
40
40
  5.5 KB packages/playwright/src/runner/rebase.ts
41
41
  3.4 KB packages/playwright/src/runner/reporters.ts
42
42
  2.4 KB packages/playwright/src/runner/reporterTestRun.ts
43
43
  1.6 KB packages/playwright/src/runner/sigIntWatcher.ts
44
44
  3.5 KB packages/playwright/src/runner/taskRunner.ts
45
- 15.9 KB packages/playwright/src/runner/tasks.ts
45
+ 16.1 KB packages/playwright/src/runner/tasks.ts
46
46
  2.6 KB packages/playwright/src/runner/testDurations.ts
47
47
  4.4 KB packages/playwright/src/runner/testGroups.ts
48
48
  13.2 KB packages/playwright/src/runner/testRunner.ts
@@ -52,12 +52,13 @@
52
52
  13.0 KB packages/playwright/src/runner/watchMode.ts
53
53
  2.1 KB packages/playwright/src/runner/workerHost.ts
54
54
 
55
- ## External (9)
55
+ ## External (10)
56
56
  ../common
57
57
  ../loader/loaderProcessEntry.js
58
58
  ../transform/babelBundle
59
59
  ../util
60
60
  ../worker/workerProcessEntry.js
61
+ ./session
61
62
  ./workerStandby
62
63
  playwright-core
63
64
  playwright-core/lib/coreBundle