playwright-core 1.54.0-alpha-2025-06-23 → 1.54.0-alpha-2025-06-25

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 (44) hide show
  1. package/ThirdPartyNotices.txt +3 -3
  2. package/browsers.json +4 -4
  3. package/lib/cli/programWithTestStub.js +1 -1
  4. package/lib/client/elementHandle.js +0 -4
  5. package/lib/client/locator.js +2 -1
  6. package/lib/generated/injectedScriptSource.js +1 -1
  7. package/lib/protocol/validator.js +6 -4
  8. package/lib/remote/playwrightServer.js +5 -9
  9. package/lib/server/android/android.js +2 -2
  10. package/lib/server/bidi/bidiPage.js +2 -2
  11. package/lib/server/browser.js +1 -1
  12. package/lib/server/browserContext.js +3 -3
  13. package/lib/server/browserType.js +3 -3
  14. package/lib/server/chromium/chromium.js +7 -9
  15. package/lib/server/chromium/crPage.js +2 -3
  16. package/lib/server/chromium/videoRecorder.js +1 -1
  17. package/lib/server/dispatchers/elementHandlerDispatcher.js +0 -3
  18. package/lib/server/dispatchers/frameDispatcher.js +3 -0
  19. package/lib/server/dispatchers/localUtilsDispatcher.js +2 -3
  20. package/lib/server/dom.js +20 -50
  21. package/lib/server/electron/electron.js +1 -1
  22. package/lib/server/fetch.js +1 -1
  23. package/lib/server/firefox/ffPage.js +2 -2
  24. package/lib/server/frames.js +77 -58
  25. package/lib/server/input.js +11 -11
  26. package/lib/server/page.js +5 -8
  27. package/lib/server/progress.js +41 -21
  28. package/lib/server/recorder/recorderApp.js +1 -1
  29. package/lib/server/registry/index.js +1 -1
  30. package/lib/server/registry/oopDownloadBrowserMain.js +1 -1
  31. package/lib/server/screenshotter.js +1 -1
  32. package/lib/server/trace/viewer/traceViewer.js +1 -1
  33. package/lib/server/transport.js +0 -2
  34. package/lib/server/utils/network.js +13 -14
  35. package/lib/server/webkit/wkPage.js +1 -1
  36. package/lib/utils/isomorphic/protocolMetainfo.js +1 -1
  37. package/lib/utilsBundleImpl/index.js +160 -150
  38. package/lib/vite/traceViewer/assets/{codeMirrorModule--amfWN3K.js → codeMirrorModule-KhY1IY1h.js} +1 -1
  39. package/lib/vite/traceViewer/assets/{defaultSettingsView-BFAIqAv2.js → defaultSettingsView-h9mbAVJF.js} +45 -45
  40. package/lib/vite/traceViewer/{index.amRtOpxT.js → index.Ckw7w8kC.js} +1 -1
  41. package/lib/vite/traceViewer/index.html +2 -2
  42. package/lib/vite/traceViewer/uiMode.html +2 -2
  43. package/lib/vite/traceViewer/{uiMode.hufuL2u6.js → uiMode.wzqlDRzc.js} +1 -1
  44. package/package.json +1 -1
@@ -484,7 +484,7 @@ class Frame extends import_instrumentation.SdkObject {
484
484
  }));
485
485
  }
486
486
  redirectNavigation(url, documentId, referer) {
487
- const controller = new import_progress.ProgressController((0, import_instrumentation.serverSideCallMetadata)(), this, "strict");
487
+ const controller = new import_progress.ProgressController((0, import_instrumentation.serverSideCallMetadata)(), this);
488
488
  const data = {
489
489
  url,
490
490
  gotoPromise: controller.run((progress) => this.gotoImpl(progress, url, { referer }), 0)
@@ -493,7 +493,7 @@ class Frame extends import_instrumentation.SdkObject {
493
493
  data.gotoPromise.finally(() => this._redirectedNavigations.delete(documentId));
494
494
  }
495
495
  async goto(metadata, url, options) {
496
- const controller = new import_progress.ProgressController(metadata, this, "strict");
496
+ const controller = new import_progress.ProgressController(metadata, this);
497
497
  return controller.run((progress) => {
498
498
  const constructedNavigationURL = (0, import_utils.constructURLBasedOnBaseURL)(this._page.browserContext._options.baseURL, url);
499
499
  return this.raceNavigationAction(progress, async () => this.gotoImpl(progress, constructedNavigationURL, options));
@@ -603,7 +603,7 @@ class Frame extends import_instrumentation.SdkObject {
603
603
  return this.selectors.query(selector, options);
604
604
  }
605
605
  async waitForSelector(metadata, selector, options, scope) {
606
- const controller = new import_progress.ProgressController(metadata, this, "strict");
606
+ const controller = new import_progress.ProgressController(metadata, this);
607
607
  return controller.run(async (progress) => {
608
608
  if (options.visibility)
609
609
  throw new Error("options.visibility is not supported, did you mean options.state?");
@@ -720,7 +720,7 @@ class Frame extends import_instrumentation.SdkObject {
720
720
  }
721
721
  }
722
722
  async setContent(metadata, html, options) {
723
- const controller = new import_progress.ProgressController(metadata, this, "strict");
723
+ const controller = new import_progress.ProgressController(metadata, this);
724
724
  return controller.run(async (progress) => {
725
725
  await this.raceNavigationAction(progress, async () => {
726
726
  const waitUntil = options.waitUntil === void 0 ? "load" : options.waitUntil;
@@ -953,19 +953,19 @@ class Frame extends import_instrumentation.SdkObject {
953
953
  });
954
954
  }
955
955
  async click(metadata, selector, options) {
956
- const controller = new import_progress.ProgressController(metadata, this, "strict");
956
+ const controller = new import_progress.ProgressController(metadata, this);
957
957
  return controller.run(async (progress) => {
958
958
  return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._click(progress, { ...options, waitAfter: !options.noWaitAfter })));
959
959
  }, options.timeout);
960
960
  }
961
961
  async dblclick(metadata, selector, options) {
962
- const controller = new import_progress.ProgressController(metadata, this, "strict");
962
+ const controller = new import_progress.ProgressController(metadata, this);
963
963
  return controller.run(async (progress) => {
964
964
  return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._dblclick(progress, options)));
965
965
  }, options.timeout);
966
966
  }
967
967
  async dragAndDrop(metadata, source, target, options) {
968
- const controller = new import_progress.ProgressController(metadata, this, "strict");
968
+ const controller = new import_progress.ProgressController(metadata, this);
969
969
  await controller.run(async (progress) => {
970
970
  dom.assertDone(await this._retryWithProgressIfNotConnected(progress, source, options.strict, !options.force, async (handle) => {
971
971
  return handle._retryPointerAction(progress, "move and down", false, async (point) => {
@@ -990,7 +990,7 @@ class Frame extends import_instrumentation.SdkObject {
990
990
  }, options.timeout);
991
991
  }
992
992
  async tap(metadata, selector, options) {
993
- const controller = new import_progress.ProgressController(metadata, this, "strict");
993
+ const controller = new import_progress.ProgressController(metadata, this);
994
994
  return controller.run(async (progress) => {
995
995
  if (!this._page.browserContext._options.hasTouch)
996
996
  throw new Error("The page does not support tap. Use hasTouch context option to enable touch support.");
@@ -998,23 +998,52 @@ class Frame extends import_instrumentation.SdkObject {
998
998
  }, options.timeout);
999
999
  }
1000
1000
  async fill(metadata, selector, value, options) {
1001
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1001
+ const controller = new import_progress.ProgressController(metadata, this);
1002
1002
  return controller.run(async (progress) => {
1003
1003
  return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._fill(progress, value, options)));
1004
1004
  }, options.timeout);
1005
1005
  }
1006
1006
  async focus(metadata, selector, options) {
1007
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1007
+ const controller = new import_progress.ProgressController(metadata, this);
1008
1008
  await controller.run(async (progress) => {
1009
1009
  dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, true, (handle) => handle._focus(progress)));
1010
1010
  }, options.timeout);
1011
1011
  }
1012
1012
  async blur(metadata, selector, options) {
1013
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1013
+ const controller = new import_progress.ProgressController(metadata, this);
1014
1014
  await controller.run(async (progress) => {
1015
1015
  dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, true, (handle) => handle._blur(progress)));
1016
1016
  }, options.timeout);
1017
1017
  }
1018
+ async generateLocatorString(metadata, selector) {
1019
+ const controller = new import_progress.ProgressController(metadata, this);
1020
+ return controller.run(async (progress) => {
1021
+ const element = await progress.race(this.selectors.query(selector));
1022
+ if (!element)
1023
+ throw new Error(`No element matching ${this._asLocator(selector)}`);
1024
+ const generated = await progress.race(element.evaluateInUtility(async ([injected, node]) => {
1025
+ return injected.generateSelectorSimple(node);
1026
+ }, {}));
1027
+ if (!generated)
1028
+ throw new Error(`Unable to generate locator for ${this._asLocator(selector)}`);
1029
+ let frame = element._frame;
1030
+ const result = [generated];
1031
+ while (frame?.parentFrame()) {
1032
+ const frameElement = await progress.race(frame.frameElement());
1033
+ if (frameElement) {
1034
+ const generated2 = await progress.race(frameElement.evaluateInUtility(async ([injected, node]) => {
1035
+ return injected.generateSelectorSimple(node);
1036
+ }, {}));
1037
+ frameElement.dispose();
1038
+ if (generated2 === "error:notconnected" || !generated2)
1039
+ throw new Error(`Unable to generate locator for ${this._asLocator(selector)}`);
1040
+ result.push(generated2);
1041
+ }
1042
+ frame = frame.parentFrame();
1043
+ }
1044
+ return (0, import_utils.asLocator)(this._page.browserContext._browser.sdkLanguage(), result.reverse().join(" >> internal:control=enter-frame >> "));
1045
+ });
1046
+ }
1018
1047
  async textContent(metadata, selector, options, scope) {
1019
1048
  return this._callOnElementOnceMatches(metadata, selector, (injected, element) => element.textContent, void 0, options, scope);
1020
1049
  }
@@ -1065,7 +1094,7 @@ class Frame extends import_instrumentation.SdkObject {
1065
1094
  return result.matches;
1066
1095
  }
1067
1096
  async isVisible(metadata, selector, options = {}, scope) {
1068
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1097
+ const controller = new import_progress.ProgressController(metadata, this);
1069
1098
  return controller.run(async (progress) => {
1070
1099
  progress.log(` checking visibility of ${this._asLocator(selector)}`);
1071
1100
  return await this.isVisibleInternal(progress, selector, options, scope);
@@ -1103,54 +1132,54 @@ class Frame extends import_instrumentation.SdkObject {
1103
1132
  return this._elementState(metadata, selector, "checked", options, scope);
1104
1133
  }
1105
1134
  async hover(metadata, selector, options) {
1106
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1135
+ const controller = new import_progress.ProgressController(metadata, this);
1107
1136
  return controller.run(async (progress) => {
1108
1137
  return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._hover(progress, options)));
1109
1138
  }, options.timeout);
1110
1139
  }
1111
1140
  async selectOption(metadata, selector, elements, values, options) {
1112
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1141
+ const controller = new import_progress.ProgressController(metadata, this);
1113
1142
  return controller.run(async (progress) => {
1114
1143
  return await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._selectOption(progress, elements, values, options));
1115
1144
  }, options.timeout);
1116
1145
  }
1117
1146
  async setInputFiles(metadata, selector, params) {
1118
1147
  const inputFileItems = await (0, import_fileUploadUtils.prepareFilesForUpload)(this, params);
1119
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1148
+ const controller = new import_progress.ProgressController(metadata, this);
1120
1149
  return controller.run(async (progress) => {
1121
1150
  return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, params.strict, true, (handle) => handle._setInputFiles(progress, inputFileItems)));
1122
1151
  }, params.timeout);
1123
1152
  }
1124
1153
  async type(metadata, selector, text, options) {
1125
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1154
+ const controller = new import_progress.ProgressController(metadata, this);
1126
1155
  return controller.run(async (progress) => {
1127
1156
  return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, true, (handle) => handle._type(progress, text, options)));
1128
1157
  }, options.timeout);
1129
1158
  }
1130
1159
  async press(metadata, selector, key, options) {
1131
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1160
+ const controller = new import_progress.ProgressController(metadata, this);
1132
1161
  return controller.run(async (progress) => {
1133
1162
  return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, true, (handle) => handle._press(progress, key, options)));
1134
1163
  }, options.timeout);
1135
1164
  }
1136
1165
  async check(metadata, selector, options) {
1137
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1166
+ const controller = new import_progress.ProgressController(metadata, this);
1138
1167
  return controller.run(async (progress) => {
1139
1168
  return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._setChecked(progress, true, options)));
1140
1169
  }, options.timeout);
1141
1170
  }
1142
1171
  async uncheck(metadata, selector, options) {
1143
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1172
+ const controller = new import_progress.ProgressController(metadata, this);
1144
1173
  return controller.run(async (progress) => {
1145
1174
  return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, !options.force, (handle) => handle._setChecked(progress, false, options)));
1146
1175
  }, options.timeout);
1147
1176
  }
1148
1177
  async waitForTimeout(metadata, timeout) {
1149
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1178
+ const controller = new import_progress.ProgressController(metadata, this);
1150
1179
  return controller.run((progress) => progress.wait(timeout));
1151
1180
  }
1152
1181
  async ariaSnapshot(metadata, selector, options) {
1153
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1182
+ const controller = new import_progress.ProgressController(metadata, this);
1154
1183
  return controller.run(async (progress) => {
1155
1184
  return await this._retryWithProgressIfNotConnected(progress, selector, true, true, (handle) => progress.race(handle.ariaSnapshot(options)));
1156
1185
  }, options.timeout);
@@ -1162,43 +1191,32 @@ class Frame extends import_instrumentation.SdkObject {
1162
1191
  return result;
1163
1192
  }
1164
1193
  async _expectImpl(metadata, selector, options) {
1194
+ const controller = new import_progress.ProgressController(metadata, this);
1165
1195
  const lastIntermediateResult = { isSet: false };
1166
- try {
1167
- let timeout = options.timeout;
1168
- const start = timeout > 0 ? (0, import_utils.monotonicTime)() : 0;
1169
- await new import_progress.ProgressController(metadata, this, "strict").run(async (progress) => {
1170
- progress.log(`${(0, import_utils.renderTitleForCall)(metadata)}${timeout ? ` with timeout ${timeout}ms` : ""}`);
1171
- if (selector)
1172
- progress.log(`waiting for ${this._asLocator(selector)}`);
1173
- await this._page.performActionPreChecks(progress);
1174
- }, timeout);
1196
+ return await controller.run(async (progress) => {
1197
+ progress.log(`${(0, import_utils.renderTitleForCall)(metadata)}${options.timeout ? ` with timeout ${options.timeout}ms` : ""}`);
1198
+ if (selector)
1199
+ progress.log(`waiting for ${this._asLocator(selector)}`);
1200
+ await this._page.performActionPreChecks(progress);
1201
+ progress.legacyDisableTimeout();
1175
1202
  try {
1176
- const resultOneShot = await new import_progress.ProgressController(metadata, this, "strict").run(async (progress) => {
1177
- return await this._expectInternal(progress, selector, options, lastIntermediateResult);
1178
- });
1203
+ const resultOneShot = await this._expectInternal(progress, selector, options, lastIntermediateResult, true);
1179
1204
  if (resultOneShot.matches !== options.isNot)
1180
1205
  return resultOneShot;
1181
1206
  } catch (e) {
1182
1207
  if (this.isNonRetriableError(e))
1183
1208
  throw e;
1184
1209
  }
1185
- if (timeout > 0) {
1186
- const elapsed = (0, import_utils.monotonicTime)() - start;
1187
- timeout -= elapsed;
1188
- }
1189
- if (timeout < 0)
1190
- return { matches: options.isNot, log: (0, import_callLog.compressCallLog)(metadata.log), timedOut: true, received: lastIntermediateResult.received };
1191
- return await new import_progress.ProgressController(metadata, this, "strict").run(async (progress) => {
1192
- return await this.retryWithProgressAndTimeouts(progress, [100, 250, 500, 1e3], async (continuePolling) => {
1193
- await this._page.performActionPreChecks(progress);
1194
- const { matches, received } = await this._expectInternal(progress, selector, options, lastIntermediateResult);
1195
- if (matches === options.isNot) {
1196
- return continuePolling;
1197
- }
1198
- return { matches, received };
1199
- });
1200
- }, timeout);
1201
- } catch (e) {
1210
+ progress.legacyEnableTimeout();
1211
+ return await this.retryWithProgressAndTimeouts(progress, [100, 250, 500, 1e3], async (continuePolling) => {
1212
+ await this._page.performActionPreChecks(progress);
1213
+ const { matches, received } = await this._expectInternal(progress, selector, options, lastIntermediateResult, false);
1214
+ if (matches === options.isNot) {
1215
+ return continuePolling;
1216
+ }
1217
+ return { matches, received };
1218
+ });
1219
+ }, options.timeout).catch((e) => {
1202
1220
  if (js.isJavaScriptErrorInEvaluate(e) || (0, import_selectorParser.isInvalidSelectorError)(e))
1203
1221
  throw e;
1204
1222
  const result = { matches: options.isNot, log: (0, import_callLog.compressCallLog)(metadata.log) };
@@ -1207,15 +1225,16 @@ class Frame extends import_instrumentation.SdkObject {
1207
1225
  if (e instanceof import_errors.TimeoutError)
1208
1226
  result.timedOut = true;
1209
1227
  return result;
1210
- }
1228
+ });
1211
1229
  }
1212
- async _expectInternal(progress, selector, options, lastIntermediateResult) {
1213
- const selectorInFrame = selector ? await progress.race(this.selectors.resolveFrameForSelector(selector, { strict: true })) : void 0;
1230
+ async _expectInternal(progress, selector, options, lastIntermediateResult, noAbort) {
1231
+ const race = (p) => noAbort ? p : progress.race(p);
1232
+ const selectorInFrame = selector ? await race(this.selectors.resolveFrameForSelector(selector, { strict: true })) : void 0;
1214
1233
  const { frame, info } = selectorInFrame || { frame: this, info: void 0 };
1215
1234
  const world = options.expression === "to.have.property" ? "main" : info?.world ?? "utility";
1216
- const context = await progress.race(frame._context(world));
1217
- const injected = await progress.race(context.injectedScript());
1218
- const { log, matches, received, missingReceived } = await progress.race(injected.evaluate(async (injected2, { info: info2, options: options2, callId }) => {
1235
+ const context = await race(frame._context(world));
1236
+ const injected = await race(context.injectedScript());
1237
+ const { log, matches, received, missingReceived } = await race(injected.evaluate(async (injected2, { info: info2, options: options2, callId }) => {
1219
1238
  const elements = info2 ? injected2.querySelectorAll(info2.parsed, document) : [];
1220
1239
  if (callId)
1221
1240
  injected2.markTargetElements(new Set(elements), callId);
@@ -1240,7 +1259,7 @@ class Frame extends import_instrumentation.SdkObject {
1240
1259
  return { matches, received };
1241
1260
  }
1242
1261
  async waitForFunctionExpression(metadata, expression, isFunction, arg, options) {
1243
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1262
+ const controller = new import_progress.ProgressController(metadata, this);
1244
1263
  return controller.run((progress) => this.waitForFunctionExpressionImpl(progress, expression, isFunction, arg, options, "main"), options.timeout);
1245
1264
  }
1246
1265
  async waitForFunctionExpressionImpl(progress, expression, isFunction, arg, options, world = "main") {
@@ -1337,7 +1356,7 @@ class Frame extends import_instrumentation.SdkObject {
1337
1356
  this._parentFrame = null;
1338
1357
  }
1339
1358
  async _callOnElementOnceMatches(metadata, selector, body, taskData, options, scope) {
1340
- const controller = new import_progress.ProgressController(metadata, this, "strict");
1359
+ const controller = new import_progress.ProgressController(metadata, this);
1341
1360
  return controller.run(async (progress) => {
1342
1361
  const callbackText = body.toString();
1343
1362
  progress.log(`waiting for ${this._asLocator(selector)}`);
@@ -49,7 +49,7 @@ class Keyboard {
49
49
  this._page = page;
50
50
  }
51
51
  async down(metadata, key) {
52
- const controller = new import_progress.ProgressController(metadata, this._page, "strict");
52
+ const controller = new import_progress.ProgressController(metadata, this._page);
53
53
  return controller.run((progress) => this._down(progress, key));
54
54
  }
55
55
  async _down(progress, key) {
@@ -71,7 +71,7 @@ class Keyboard {
71
71
  return description;
72
72
  }
73
73
  async up(metadata, key) {
74
- const controller = new import_progress.ProgressController(metadata, this._page, "strict");
74
+ const controller = new import_progress.ProgressController(metadata, this._page);
75
75
  return controller.run((progress) => this._up(progress, key));
76
76
  }
77
77
  async _up(progress, key) {
@@ -82,14 +82,14 @@ class Keyboard {
82
82
  await this._raw.keyup(progress, this._pressedModifiers, key, description);
83
83
  }
84
84
  async insertText(metadata, text) {
85
- const controller = new import_progress.ProgressController(metadata, this._page, "strict");
85
+ const controller = new import_progress.ProgressController(metadata, this._page);
86
86
  return controller.run((progress) => this._insertText(progress, text));
87
87
  }
88
88
  async _insertText(progress, text) {
89
89
  await this._raw.sendText(progress, text);
90
90
  }
91
91
  async type(metadata, text, options) {
92
- const controller = new import_progress.ProgressController(metadata, this._page, "strict");
92
+ const controller = new import_progress.ProgressController(metadata, this._page);
93
93
  return controller.run((progress) => this._type(progress, text, options));
94
94
  }
95
95
  async _type(progress, text, options) {
@@ -105,7 +105,7 @@ class Keyboard {
105
105
  }
106
106
  }
107
107
  async press(metadata, key, options) {
108
- const controller = new import_progress.ProgressController(metadata, this._page, "strict");
108
+ const controller = new import_progress.ProgressController(metadata, this._page);
109
109
  return controller.run((progress) => this._press(progress, key, options));
110
110
  }
111
111
  async _press(progress, key, options = {}) {
@@ -177,7 +177,7 @@ class Mouse {
177
177
  return { x: this._x, y: this._y };
178
178
  }
179
179
  async move(metadata, x, y, options) {
180
- const controller = new import_progress.ProgressController(metadata, this._page, "strict");
180
+ const controller = new import_progress.ProgressController(metadata, this._page);
181
181
  return controller.run((progress) => this._move(progress, x, y, options));
182
182
  }
183
183
  async _move(progress, x, y, options = {}) {
@@ -193,7 +193,7 @@ class Mouse {
193
193
  }
194
194
  }
195
195
  async down(metadata, options) {
196
- const controller = new import_progress.ProgressController(metadata, this._page, "strict");
196
+ const controller = new import_progress.ProgressController(metadata, this._page);
197
197
  return controller.run((progress) => this._down(progress, options));
198
198
  }
199
199
  async _down(progress, options = {}) {
@@ -203,7 +203,7 @@ class Mouse {
203
203
  await this._raw.down(progress, this._x, this._y, this._lastButton, this._buttons, this._keyboard._modifiers(), clickCount);
204
204
  }
205
205
  async up(metadata, options) {
206
- const controller = new import_progress.ProgressController(metadata, this._page, "strict");
206
+ const controller = new import_progress.ProgressController(metadata, this._page);
207
207
  return controller.run((progress) => this._up(progress, options));
208
208
  }
209
209
  async _up(progress, options = {}) {
@@ -213,7 +213,7 @@ class Mouse {
213
213
  await this._raw.up(progress, this._x, this._y, button, this._buttons, this._keyboard._modifiers(), clickCount);
214
214
  }
215
215
  async click(metadata, x, y, options) {
216
- const controller = new import_progress.ProgressController(metadata, this._page, "strict");
216
+ const controller = new import_progress.ProgressController(metadata, this._page);
217
217
  return controller.run((progress) => this._click(progress, x, y, options));
218
218
  }
219
219
  async _click(progress, x, y, options = {}) {
@@ -238,7 +238,7 @@ class Mouse {
238
238
  }
239
239
  }
240
240
  async wheel(metadata, deltaX, deltaY) {
241
- const controller = new import_progress.ProgressController(metadata, this._page, "strict");
241
+ const controller = new import_progress.ProgressController(metadata, this._page);
242
242
  return controller.run(async (progress) => {
243
243
  await this._raw.wheel(progress, this._x, this._y, this._buttons, this._keyboard._modifiers(), deltaX, deltaY);
244
244
  });
@@ -295,7 +295,7 @@ class Touchscreen {
295
295
  this._page = page;
296
296
  }
297
297
  async tap(metadata, x, y) {
298
- const controller = new import_progress.ProgressController(metadata, this._page, "strict");
298
+ const controller = new import_progress.ProgressController(metadata, this._page);
299
299
  return controller.run((progress) => this._tap(progress, x, y));
300
300
  }
301
301
  async _tap(progress, x, y) {
@@ -249,7 +249,7 @@ class Page extends import_instrumentation.SdkObject {
249
249
  this.emitOnContextOnceInitialized(import_browserContext.BrowserContext.Events.Console, message);
250
250
  }
251
251
  async reload(metadata, options) {
252
- const controller = new import_progress.ProgressController(metadata, this, "strict");
252
+ const controller = new import_progress.ProgressController(metadata, this);
253
253
  return controller.run((progress) => this.mainFrame().raceNavigationAction(progress, async () => {
254
254
  const [response] = await Promise.all([
255
255
  // Reload must be a new document, and should not be confused with a stray pushState.
@@ -260,7 +260,7 @@ class Page extends import_instrumentation.SdkObject {
260
260
  }), options.timeout);
261
261
  }
262
262
  async goBack(metadata, options) {
263
- const controller = new import_progress.ProgressController(metadata, this, "strict");
263
+ const controller = new import_progress.ProgressController(metadata, this);
264
264
  return controller.run((progress) => this.mainFrame().raceNavigationAction(progress, async () => {
265
265
  let error;
266
266
  const waitPromise = this.mainFrame()._waitForNavigation(progress, false, options).catch((e) => {
@@ -280,7 +280,7 @@ class Page extends import_instrumentation.SdkObject {
280
280
  }), options.timeout);
281
281
  }
282
282
  async goForward(metadata, options) {
283
- const controller = new import_progress.ProgressController(metadata, this, "strict");
283
+ const controller = new import_progress.ProgressController(metadata, this);
284
284
  return controller.run((progress) => this.mainFrame().raceNavigationAction(progress, async () => {
285
285
  let error;
286
286
  const waitPromise = this.mainFrame()._waitForNavigation(progress, false, options).catch((e) => {
@@ -321,9 +321,7 @@ class Page extends import_instrumentation.SdkObject {
321
321
  }
322
322
  async performActionPreChecks(progress) {
323
323
  await this._performWaitForNavigationCheck(progress);
324
- progress.throwIfAborted();
325
324
  await this._performLocatorHandlersCheckpoint(progress);
326
- progress.throwIfAborted();
327
325
  await this._performWaitForNavigationCheck(progress);
328
326
  }
329
327
  async _performWaitForNavigationCheck(progress) {
@@ -355,7 +353,6 @@ class Page extends import_instrumentation.SdkObject {
355
353
  ++this._locatorHandlerRunningCounter;
356
354
  progress.log(` found ${(0, import_utils2.asLocator)(this.browserContext._browser.sdkLanguage(), handler.selector)}, intercepting action to run the handler`);
357
355
  const promise = handler.resolved.then(async () => {
358
- progress.throwIfAborted();
359
356
  if (!handler.noWaitAfter) {
360
357
  progress.log(` locator handler has finished, waiting for ${(0, import_utils2.asLocator)(this.browserContext._browser.sdkLanguage(), handler.selector)} to be hidden`);
361
358
  await this.mainFrame().waitForSelectorInternal(progress, handler.selector, false, { state: "hidden" });
@@ -450,7 +447,7 @@ class Page extends import_instrumentation.SdkObject {
450
447
  return await this.screenshotter.screenshotPage(progress, options || {});
451
448
  };
452
449
  const comparator = (0, import_comparators.getComparator)("image/png");
453
- const controller = new import_progress.ProgressController(metadata, this, "strict");
450
+ const controller = new import_progress.ProgressController(metadata, this);
454
451
  if (!options.expected && options.isNot)
455
452
  return { errorMessage: '"not" matcher requires expected result' };
456
453
  try {
@@ -630,7 +627,7 @@ class Page extends import_instrumentation.SdkObject {
630
627
  this._isServerSideOnly = true;
631
628
  }
632
629
  snapshotForAI(metadata) {
633
- const controller = new import_progress.ProgressController(metadata, this, "strict");
630
+ const controller = new import_progress.ProgressController(metadata, this);
634
631
  return controller.run(async (progress) => {
635
632
  this.lastSnapshotFrameIds = [];
636
633
  const snapshot = await snapshotFrameForAI(progress, this.mainFrame(), 0, this.lastSnapshotFrameIds);
@@ -26,7 +26,7 @@ var import_errors = require("./errors");
26
26
  var import_utils = require("../utils");
27
27
  var import_manualPromise = require("../utils/isomorphic/manualPromise");
28
28
  class ProgressController {
29
- constructor(metadata, sdkObject, strictMode) {
29
+ constructor(metadata, sdkObject) {
30
30
  this._forceAbortPromise = new import_manualPromise.ManualPromise();
31
31
  this._donePromise = new import_manualPromise.ManualPromise();
32
32
  // Cleanups to be run only in the case of abort.
@@ -38,8 +38,7 @@ class ProgressController {
38
38
  // progress only finishes after the inner callback exits, guaranteeing no work after the timeout.
39
39
  this._strictMode = false;
40
40
  this._state = "before";
41
- this._deadline = 0;
42
- this._strictMode = strictMode === "strict";
41
+ this._strictMode = !process.env.PLAYWRIGHT_LEGACY_TIMEOUTS;
43
42
  this.metadata = metadata;
44
43
  this.sdkObject = sdkObject;
45
44
  this.instrumentation = sdkObject.instrumentation;
@@ -59,27 +58,44 @@ class ProgressController {
59
58
  await this._donePromise;
60
59
  }
61
60
  async run(task, timeout) {
62
- this._deadline = timeout ? (0, import_utils.monotonicTime)() + timeout : 0;
63
61
  (0, import_utils.assert)(this._state === "before");
64
62
  this._state = "running";
65
63
  this.sdkObject.attribution.context?._activeProgressControllers.add(this);
64
+ const deadline = timeout ? Math.min((0, import_utils.monotonicTime)() + timeout, 2147483647) : 0;
65
+ const timeoutError = new import_errors.TimeoutError(`Timeout ${timeout}ms exceeded.`);
66
+ let timer;
67
+ const startTimer = () => {
68
+ if (!deadline)
69
+ return;
70
+ const onTimeout = () => {
71
+ if (this._state === "running") {
72
+ this._state = { error: timeoutError };
73
+ this._forceAbortPromise.reject(timeoutError);
74
+ }
75
+ };
76
+ const remaining = deadline - (0, import_utils.monotonicTime)();
77
+ if (remaining <= 0)
78
+ onTimeout();
79
+ else
80
+ timer = setTimeout(onTimeout, remaining);
81
+ };
66
82
  const progress = {
67
83
  log: (message) => {
68
84
  if (this._state === "running")
69
85
  this.metadata.log.push(message);
70
86
  this.instrumentation.onCallLog(this.sdkObject, this.metadata, this._logName, message);
71
87
  },
72
- timeUntilDeadline: () => this._deadline ? this._deadline - (0, import_utils.monotonicTime)() : 2147483647,
73
- // 2^31-1 safe setTimeout in Node.
74
88
  cleanupWhenAborted: (cleanup) => {
89
+ if (this._strictMode) {
90
+ if (this._state !== "running")
91
+ throw new Error("Internal error: cannot register cleanup after operation has finished.");
92
+ this._cleanups.push(cleanup);
93
+ return;
94
+ }
75
95
  if (this._state === "running")
76
96
  this._cleanups.push(cleanup);
77
97
  else
78
- runCleanup(cleanup);
79
- },
80
- throwIfAborted: () => {
81
- if (typeof this._state === "object")
82
- throw this._state.error;
98
+ runCleanup(typeof this._state === "object" ? this._state.error : void 0, cleanup);
83
99
  },
84
100
  metadata: this.metadata,
85
101
  race: (promise) => {
@@ -96,15 +112,19 @@ class ProgressController {
96
112
  let timer2;
97
113
  const promise = new Promise((f) => timer2 = setTimeout(f, timeout2));
98
114
  return progress.race(promise).finally(() => clearTimeout(timer2));
115
+ },
116
+ legacyDisableTimeout: () => {
117
+ if (this._strictMode)
118
+ return;
119
+ clearTimeout(timer);
120
+ },
121
+ legacyEnableTimeout: () => {
122
+ if (this._strictMode)
123
+ return;
124
+ startTimer();
99
125
  }
100
126
  };
101
- const timeoutError = new import_errors.TimeoutError(`Timeout ${timeout}ms exceeded.`);
102
- const timer = setTimeout(() => {
103
- if (this._state === "running") {
104
- this._state = { error: timeoutError };
105
- this._forceAbortPromise.reject(timeoutError);
106
- }
107
- }, progress.timeUntilDeadline());
127
+ startTimer();
108
128
  try {
109
129
  const promise = task(progress);
110
130
  const result = this._strictMode ? await promise : await Promise.race([promise, this._forceAbortPromise]);
@@ -112,7 +132,7 @@ class ProgressController {
112
132
  return result;
113
133
  } catch (error) {
114
134
  this._state = { error };
115
- await Promise.all(this._cleanups.splice(0).map(runCleanup));
135
+ await Promise.all(this._cleanups.splice(0).map((cleanup) => runCleanup(error, cleanup)));
116
136
  throw error;
117
137
  } finally {
118
138
  this.sdkObject.attribution.context?._activeProgressControllers.delete(this);
@@ -121,9 +141,9 @@ class ProgressController {
121
141
  }
122
142
  }
123
143
  }
124
- async function runCleanup(cleanup) {
144
+ async function runCleanup(error, cleanup) {
125
145
  try {
126
- await cleanup();
146
+ await cleanup(error);
127
147
  } catch (e) {
128
148
  }
129
149
  }
@@ -127,7 +127,7 @@ class RecorderApp extends import_events.EventEmitter {
127
127
  timeout: 0
128
128
  }
129
129
  });
130
- const controller = new import_progress.ProgressController((0, import_instrumentation.serverSideCallMetadata)(), context._browser, "strict");
130
+ const controller = new import_progress.ProgressController((0, import_instrumentation.serverSideCallMetadata)(), context._browser);
131
131
  await controller.run(async (progress) => {
132
132
  await context._browser._defaultContext._loadDefaultContextAsIs(progress);
133
133
  });
@@ -1089,7 +1089,7 @@ ${e.stack}`);
1089
1089
  async _installMSEdgeChannel(channel, scripts) {
1090
1090
  const scriptArgs = [];
1091
1091
  if (process.platform !== "linux") {
1092
- const products = lowercaseAllKeys(JSON.parse(await (0, import_network.fetchData)({ url: "https://edgeupdates.microsoft.com/api/products" })));
1092
+ const products = lowercaseAllKeys(JSON.parse(await (0, import_network.fetchData)(void 0, { url: "https://edgeupdates.microsoft.com/api/products" })));
1093
1093
  const productName = {
1094
1094
  "msedge": "Stable",
1095
1095
  "msedge-beta": "Beta",
@@ -47,7 +47,7 @@ function downloadFile(options) {
47
47
  headers: {
48
48
  "User-Agent": options.userAgent
49
49
  },
50
- timeout: options.socketTimeout
50
+ socketTimeout: options.socketTimeout
51
51
  }, (response) => {
52
52
  log(`-- response status code: ${response.statusCode}`);
53
53
  if (response.statusCode !== 200) {
@@ -253,7 +253,7 @@ class Screenshotter {
253
253
  }
254
254
  const cleanupHighlight = await this._maskElements(progress, options);
255
255
  const quality = format === "jpeg" ? options.quality ?? 80 : void 0;
256
- const buffer = await progress.race(this._page.delegate.takeScreenshot(progress, format, documentRect, viewportRect, quality, fitsViewport, options.scale || "device"));
256
+ const buffer = await this._page.delegate.takeScreenshot(progress, format, documentRect, viewportRect, quality, fitsViewport, options.scale || "device");
257
257
  await cleanupHighlight();
258
258
  if (shouldSetDefaultBackground)
259
259
  await progress.race(this._page.delegate.setBackgroundColor());
@@ -158,7 +158,7 @@ async function openTraceViewerApp(url, browserName, options) {
158
158
  timeout: 0
159
159
  }
160
160
  });
161
- const controller = new import_progress.ProgressController((0, import_instrumentation.serverSideCallMetadata)(), context._browser, "strict");
161
+ const controller = new import_progress.ProgressController((0, import_instrumentation.serverSideCallMetadata)(), context._browser);
162
162
  await controller.run(async (progress) => {
163
163
  await context._browser._defaultContext._loadDefaultContextAsIs(progress);
164
164
  });
@@ -43,8 +43,6 @@ class WebSocketTransport {
43
43
  this._ws = new import_utilsBundle.ws(url, [], {
44
44
  maxPayload: 256 * 1024 * 1024,
45
45
  // 256Mb,
46
- // Prevent internal http client error when passing negative timeout.
47
- handshakeTimeout: Math.max(progress?.timeUntilDeadline() ?? import_utils.DEFAULT_PLAYWRIGHT_TIMEOUT, 1),
48
46
  headers: options.headers,
49
47
  followRedirects: options.followRedirects,
50
48
  agent: /^(https|wss):\/\//.test(url) ? import_happyEyeballs.httpsHappyEyeballsAgent : import_happyEyeballs.httpHappyEyeballsAgent,