playwright-core 1.54.0-alpha-2025-06-15 → 1.54.0-alpha-2025-06-17

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.
@@ -18,20 +18,28 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var progress_exports = {};
20
20
  __export(progress_exports, {
21
- ProgressController: () => ProgressController
21
+ ProgressController: () => ProgressController,
22
+ isAbortError: () => isAbortError
22
23
  });
23
24
  module.exports = __toCommonJS(progress_exports);
24
25
  var import_errors = require("./errors");
25
26
  var import_utils = require("../utils");
26
27
  var import_manualPromise = require("../utils/isomorphic/manualPromise");
27
28
  class ProgressController {
28
- constructor(metadata, sdkObject) {
29
+ constructor(metadata, sdkObject, strictMode) {
29
30
  this._forceAbortPromise = new import_manualPromise.ManualPromise();
31
+ this._donePromise = new import_manualPromise.ManualPromise();
30
32
  // Cleanups to be run only in the case of abort.
31
33
  this._cleanups = [];
34
+ // Lenient mode races against the timeout. This guarantees that timeout is respected,
35
+ // but may have some work being done after the timeout due to parallel control flow.
36
+ //
37
+ // Strict mode aborts the progress and requires the code to react to it. This way,
38
+ // progress only finishes after the inner callback exits, guaranteeing no work after the timeout.
39
+ this._strictMode = false;
32
40
  this._state = "before";
33
41
  this._deadline = 0;
34
- this._timeout = 0;
42
+ this._strictMode = strictMode === "strict";
35
43
  this.metadata = metadata;
36
44
  this.sdkObject = sdkObject;
37
45
  this.instrumentation = sdkObject.instrumentation;
@@ -41,14 +49,17 @@ class ProgressController {
41
49
  setLogName(logName) {
42
50
  this._logName = logName;
43
51
  }
44
- abort(error) {
45
- this._forceAbortPromise.reject(error);
52
+ async abort(message) {
53
+ if (this._state === "running") {
54
+ const error = new AbortedError(message);
55
+ this._state = { error };
56
+ this._forceAbortPromise.reject(error);
57
+ }
58
+ if (this._strictMode)
59
+ await this._donePromise;
46
60
  }
47
61
  async run(task, timeout) {
48
- if (timeout) {
49
- this._timeout = timeout;
50
- this._deadline = timeout ? (0, import_utils.monotonicTime)() + timeout : 0;
51
- }
62
+ this._deadline = timeout ? (0, import_utils.monotonicTime)() + timeout : 0;
52
63
  (0, import_utils.assert)(this._state === "before");
53
64
  this._state = "running";
54
65
  this.sdkObject.attribution.context?._activeProgressControllers.add(this);
@@ -60,7 +71,6 @@ class ProgressController {
60
71
  },
61
72
  timeUntilDeadline: () => this._deadline ? this._deadline - (0, import_utils.monotonicTime)() : 2147483647,
62
73
  // 2^31-1 safe setTimeout in Node.
63
- isRunning: () => this._state === "running",
64
74
  cleanupWhenAborted: (cleanup) => {
65
75
  if (this._state === "running")
66
76
  this._cleanups.push(cleanup);
@@ -68,25 +78,46 @@ class ProgressController {
68
78
  runCleanup(cleanup);
69
79
  },
70
80
  throwIfAborted: () => {
71
- if (this._state === "aborted")
72
- throw new AbortedError();
81
+ if (typeof this._state === "object")
82
+ throw this._state.error;
83
+ },
84
+ metadata: this.metadata,
85
+ race: (promise) => {
86
+ const promises = Array.isArray(promise) ? promise : [promise];
87
+ return Promise.race([...promises, this._forceAbortPromise]);
73
88
  },
74
- metadata: this.metadata
89
+ raceWithCleanup: (promise, cleanup) => {
90
+ return progress.race(promise.then((result) => {
91
+ progress.cleanupWhenAborted(() => cleanup(result));
92
+ return result;
93
+ }));
94
+ },
95
+ wait: async (timeout2) => {
96
+ let timer2;
97
+ const promise = new Promise((f) => timer2 = setTimeout(f, timeout2));
98
+ return progress.race(promise).finally(() => clearTimeout(timer2));
99
+ }
75
100
  };
76
- const timeoutError = new import_errors.TimeoutError(`Timeout ${this._timeout}ms exceeded.`);
77
- const timer = setTimeout(() => this._forceAbortPromise.reject(timeoutError), progress.timeUntilDeadline());
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());
78
108
  try {
79
109
  const promise = task(progress);
80
- const result = await Promise.race([promise, this._forceAbortPromise]);
110
+ const result = this._strictMode ? await promise : await Promise.race([promise, this._forceAbortPromise]);
81
111
  this._state = "finished";
82
112
  return result;
83
- } catch (e) {
84
- this._state = "aborted";
113
+ } catch (error) {
114
+ this._state = { error };
85
115
  await Promise.all(this._cleanups.splice(0).map(runCleanup));
86
- throw e;
116
+ throw error;
87
117
  } finally {
88
118
  this.sdkObject.attribution.context?._activeProgressControllers.delete(this);
89
119
  clearTimeout(timer);
120
+ this._donePromise.resolve();
90
121
  }
91
122
  }
92
123
  }
@@ -98,7 +129,11 @@ async function runCleanup(cleanup) {
98
129
  }
99
130
  class AbortedError extends Error {
100
131
  }
132
+ function isAbortError(error) {
133
+ return error instanceof AbortedError || error instanceof import_errors.TimeoutError;
134
+ }
101
135
  // Annotate the CommonJS export names for ESM import in node:
102
136
  0 && (module.exports = {
103
- ProgressController
137
+ ProgressController,
138
+ isAbortError
104
139
  });
@@ -77,7 +77,7 @@ class RawKeyboardImpl {
77
77
  let commands = import_macEditingCommands.macEditingCommands[shortcut];
78
78
  if ((0, import_utils.isString)(commands))
79
79
  commands = [commands];
80
- await this._pageProxySession.send("Input.dispatchKeyEvent", {
80
+ await progress.race(this._pageProxySession.send("Input.dispatchKeyEvent", {
81
81
  type: "keyDown",
82
82
  modifiers: toModifiersMask(modifiers),
83
83
  windowsVirtualKeyCode: keyCode,
@@ -88,24 +88,21 @@ class RawKeyboardImpl {
88
88
  autoRepeat,
89
89
  macCommands: commands,
90
90
  isKeypad: description.location === input.keypadLocation
91
- });
92
- progress.throwIfAborted();
91
+ }));
93
92
  }
94
93
  async keyup(progress, modifiers, keyName, description) {
95
94
  const { code, key } = description;
96
- await this._pageProxySession.send("Input.dispatchKeyEvent", {
95
+ await progress.race(this._pageProxySession.send("Input.dispatchKeyEvent", {
97
96
  type: "keyUp",
98
97
  modifiers: toModifiersMask(modifiers),
99
98
  key,
100
99
  windowsVirtualKeyCode: description.keyCode,
101
100
  code,
102
101
  isKeypad: description.location === input.keypadLocation
103
- });
104
- progress.throwIfAborted();
102
+ }));
105
103
  }
106
104
  async sendText(progress, text) {
107
- await this._session.send("Page.insertText", { text });
108
- progress.throwIfAborted();
105
+ await progress.race(this._session.send("Page.insertText", { text }));
109
106
  }
110
107
  }
111
108
  class RawMouseImpl {
@@ -116,18 +113,17 @@ class RawMouseImpl {
116
113
  this._session = session;
117
114
  }
118
115
  async move(progress, x, y, button, buttons, modifiers, forClick) {
119
- await this._pageProxySession.send("Input.dispatchMouseEvent", {
116
+ await progress.race(this._pageProxySession.send("Input.dispatchMouseEvent", {
120
117
  type: "move",
121
118
  button,
122
119
  buttons: toButtonsMask(buttons),
123
120
  x,
124
121
  y,
125
122
  modifiers: toModifiersMask(modifiers)
126
- });
127
- progress.throwIfAborted();
123
+ }));
128
124
  }
129
125
  async down(progress, x, y, button, buttons, modifiers, clickCount) {
130
- await this._pageProxySession.send("Input.dispatchMouseEvent", {
126
+ await progress.race(this._pageProxySession.send("Input.dispatchMouseEvent", {
131
127
  type: "down",
132
128
  button,
133
129
  buttons: toButtonsMask(buttons),
@@ -135,11 +131,10 @@ class RawMouseImpl {
135
131
  y,
136
132
  modifiers: toModifiersMask(modifiers),
137
133
  clickCount
138
- });
139
- progress.throwIfAborted();
134
+ }));
140
135
  }
141
136
  async up(progress, x, y, button, buttons, modifiers, clickCount) {
142
- await this._pageProxySession.send("Input.dispatchMouseEvent", {
137
+ await progress.race(this._pageProxySession.send("Input.dispatchMouseEvent", {
143
138
  type: "up",
144
139
  button,
145
140
  buttons: toButtonsMask(buttons),
@@ -147,23 +142,20 @@ class RawMouseImpl {
147
142
  y,
148
143
  modifiers: toModifiersMask(modifiers),
149
144
  clickCount
150
- });
151
- progress.throwIfAborted();
145
+ }));
152
146
  }
153
147
  async wheel(progress, x, y, buttons, modifiers, deltaX, deltaY) {
154
148
  if (this._page?.browserContext._options.isMobile)
155
149
  throw new Error("Mouse wheel is not supported in mobile WebKit");
156
150
  await this._session.send("Page.updateScrollingState");
157
- await this._page.mainFrame().evaluateExpression(`new Promise(requestAnimationFrame)`, { world: "utility" });
158
- progress.throwIfAborted();
159
- await this._pageProxySession.send("Input.dispatchWheelEvent", {
151
+ await progress.race(this._page.mainFrame().evaluateExpression(`new Promise(requestAnimationFrame)`, { world: "utility" }));
152
+ await progress.race(this._pageProxySession.send("Input.dispatchWheelEvent", {
160
153
  x,
161
154
  y,
162
155
  deltaX,
163
156
  deltaY,
164
157
  modifiers: toModifiersMask(modifiers)
165
- });
166
- progress.throwIfAborted();
158
+ }));
167
159
  }
168
160
  setPage(page) {
169
161
  this._page = page;
@@ -174,12 +166,11 @@ class RawTouchscreenImpl {
174
166
  this._pageProxySession = session;
175
167
  }
176
168
  async tap(progress, x, y, modifiers) {
177
- await this._pageProxySession.send("Input.dispatchTapEvent", {
169
+ await progress.race(this._pageProxySession.send("Input.dispatchTapEvent", {
178
170
  x,
179
171
  y,
180
172
  modifiers: toModifiersMask(modifiers)
181
- });
182
- progress.throwIfAborted();
173
+ }));
183
174
  }
184
175
  }
185
176
  // Annotate the CommonJS export names for ESM import in node: