playwright-core 1.55.0-alpha-2025-07-23 → 1.55.0-alpha-2025-07-24
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/browsers.json +1 -1
- package/lib/server/dispatchers/frameDispatcher.js +1 -5
- package/lib/server/frames.js +10 -21
- package/lib/server/input.js +3 -1
- package/lib/server/page.js +11 -15
- package/lib/server/progress.js +18 -62
- package/lib/vite/recorder/index.html +1 -1
- package/lib/vite/traceViewer/index.html +1 -1
- package/lib/vite/traceViewer/uiMode.html +1 -1
- package/package.json +1 -1
package/browsers.json
CHANGED
|
@@ -212,11 +212,7 @@ class FrameDispatcher extends import_dispatcher.Dispatcher {
|
|
|
212
212
|
let expectedValue = params.expectedValue ? (0, import_jsHandleDispatcher.parseArgument)(params.expectedValue) : void 0;
|
|
213
213
|
if (params.expression === "to.match.aria" && expectedValue)
|
|
214
214
|
expectedValue = (0, import_ariaSnapshot.parseAriaSnapshotUnsafe)(import_utilsBundle.yaml, expectedValue);
|
|
215
|
-
const result = await this._frame.expect(progress, params.selector, { ...params, expectedValue }, params.timeout
|
|
216
|
-
if (result2.received !== void 0)
|
|
217
|
-
result2.received = (0, import_jsHandleDispatcher.serializeResult)(result2.received);
|
|
218
|
-
return result2;
|
|
219
|
-
});
|
|
215
|
+
const result = await this._frame.expect(progress, params.selector, { ...params, expectedValue }, params.timeout);
|
|
220
216
|
if (result.received !== void 0)
|
|
221
217
|
result.received = (0, import_jsHandleDispatcher.serializeResult)(result.received);
|
|
222
218
|
return result;
|
package/lib/server/frames.js
CHANGED
|
@@ -1121,35 +1121,17 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
1121
1121
|
async ariaSnapshot(progress, selector, options) {
|
|
1122
1122
|
return await this._retryWithProgressIfNotConnected(progress, selector, true, true, (handle) => progress.race(handle.ariaSnapshot(options)));
|
|
1123
1123
|
}
|
|
1124
|
-
|
|
1125
|
-
async expect(progress, selector, options, timeout, errorResultHandler) {
|
|
1124
|
+
async expect(progress, selector, options, timeout) {
|
|
1126
1125
|
progress.log(`${(0, import_utils.renderTitleForCall)(progress.metadata)}${timeout ? ` with timeout ${timeout}ms` : ""}`);
|
|
1127
|
-
const result = await this._expectImpl(progress, selector, options, errorResultHandler);
|
|
1128
|
-
return result;
|
|
1129
|
-
}
|
|
1130
|
-
async _expectImpl(progress, selector, options, errorResultHandler) {
|
|
1131
1126
|
const lastIntermediateResult = { isSet: false };
|
|
1132
1127
|
const fixupMetadataError = (result) => {
|
|
1133
1128
|
if (result.matches === options.isNot)
|
|
1134
1129
|
progress.metadata.error = { error: { name: "Expect", message: "Expect failed" } };
|
|
1135
1130
|
};
|
|
1136
|
-
const handleError = (e, isProgressError) => {
|
|
1137
|
-
if (js.isJavaScriptErrorInEvaluate(e) || (0, import_selectorParser.isInvalidSelectorError)(e))
|
|
1138
|
-
throw e;
|
|
1139
|
-
const result = { matches: options.isNot, log: (0, import_callLog.compressCallLog)(progress.metadata.log) };
|
|
1140
|
-
if (lastIntermediateResult.isSet)
|
|
1141
|
-
result.received = lastIntermediateResult.received;
|
|
1142
|
-
if (e instanceof import_errors.TimeoutError)
|
|
1143
|
-
result.timedOut = true;
|
|
1144
|
-
fixupMetadataError(result);
|
|
1145
|
-
return isProgressError && errorResultHandler ? errorResultHandler(result) : result;
|
|
1146
|
-
};
|
|
1147
|
-
progress.legacySetErrorHandler((e) => handleError(e, true));
|
|
1148
1131
|
try {
|
|
1149
1132
|
if (selector)
|
|
1150
1133
|
progress.log(`waiting for ${this._asLocator(selector)}`);
|
|
1151
1134
|
await this._page.performActionPreChecks(progress);
|
|
1152
|
-
progress.legacyDisableTimeout();
|
|
1153
1135
|
try {
|
|
1154
1136
|
const resultOneShot = await this._expectInternal(progress, selector, options, lastIntermediateResult, true);
|
|
1155
1137
|
if (resultOneShot.matches !== options.isNot)
|
|
@@ -1158,7 +1140,6 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
1158
1140
|
if (this.isNonRetriableError(e))
|
|
1159
1141
|
throw e;
|
|
1160
1142
|
}
|
|
1161
|
-
progress.legacyEnableTimeout();
|
|
1162
1143
|
const result = await this.retryWithProgressAndTimeouts(progress, [100, 250, 500, 1e3], async (continuePolling) => {
|
|
1163
1144
|
await this._page.performActionPreChecks(progress);
|
|
1164
1145
|
const { matches, received } = await this._expectInternal(progress, selector, options, lastIntermediateResult, false);
|
|
@@ -1170,7 +1151,15 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
1170
1151
|
fixupMetadataError(result);
|
|
1171
1152
|
return result;
|
|
1172
1153
|
} catch (e) {
|
|
1173
|
-
|
|
1154
|
+
if (js.isJavaScriptErrorInEvaluate(e) || (0, import_selectorParser.isInvalidSelectorError)(e))
|
|
1155
|
+
throw e;
|
|
1156
|
+
const result = { matches: options.isNot, log: (0, import_callLog.compressCallLog)(progress.metadata.log) };
|
|
1157
|
+
if (lastIntermediateResult.isSet)
|
|
1158
|
+
result.received = lastIntermediateResult.received;
|
|
1159
|
+
if (e instanceof import_errors.TimeoutError)
|
|
1160
|
+
result.timedOut = true;
|
|
1161
|
+
fixupMetadataError(result);
|
|
1162
|
+
return result;
|
|
1174
1163
|
}
|
|
1175
1164
|
}
|
|
1176
1165
|
async _expectInternal(progress, selector, options, lastIntermediateResult, noAbort) {
|
package/lib/server/input.js
CHANGED
|
@@ -38,6 +38,7 @@ __export(input_exports, {
|
|
|
38
38
|
module.exports = __toCommonJS(input_exports);
|
|
39
39
|
var import_utils = require("../utils");
|
|
40
40
|
var keyboardLayout = __toESM(require("./usKeyboardLayout"));
|
|
41
|
+
var import_dom = require("./dom");
|
|
41
42
|
const keypadLocation = keyboardLayout.keypadLocation;
|
|
42
43
|
const kModifiers = ["Alt", "Control", "Meta", "Shift"];
|
|
43
44
|
class Keyboard {
|
|
@@ -58,7 +59,8 @@ class Keyboard {
|
|
|
58
59
|
_keyDescriptionForString(str) {
|
|
59
60
|
const keyString = resolveSmartModifierString(str);
|
|
60
61
|
let description = usKeyboardLayout.get(keyString);
|
|
61
|
-
|
|
62
|
+
if (!description)
|
|
63
|
+
throw new import_dom.NonRecoverableDOMError(`Unknown key: "${keyString}"`);
|
|
62
64
|
const shift = this._pressedModifiers.has("Shift");
|
|
63
65
|
description = shift && description.shifted ? description.shifted : description;
|
|
64
66
|
if (this._pressedModifiers.size > 1 || !this._pressedModifiers.has("Shift") && this._pressedModifiers.size === 1)
|
package/lib/server/page.js
CHANGED
|
@@ -478,20 +478,6 @@ class Page extends import_instrumentation.SdkObject {
|
|
|
478
478
|
intermediateResult = { errorMessage: comparatorResult.errorMessage, diff: comparatorResult.diff, actual, previous };
|
|
479
479
|
return false;
|
|
480
480
|
};
|
|
481
|
-
const handleError = (e) => {
|
|
482
|
-
if (js.isJavaScriptErrorInEvaluate(e) || (0, import_selectorParser.isInvalidSelectorError)(e))
|
|
483
|
-
throw e;
|
|
484
|
-
let errorMessage = e.message;
|
|
485
|
-
if (e instanceof import_errors.TimeoutError && intermediateResult?.previous)
|
|
486
|
-
errorMessage = `Failed to take two consecutive stable screenshots.`;
|
|
487
|
-
return {
|
|
488
|
-
log: (0, import_callLog.compressCallLog)(e.message ? [...progress.metadata.log, e.message] : progress.metadata.log),
|
|
489
|
-
...intermediateResult,
|
|
490
|
-
errorMessage,
|
|
491
|
-
timedOut: e instanceof import_errors.TimeoutError
|
|
492
|
-
};
|
|
493
|
-
};
|
|
494
|
-
progress.legacySetErrorHandler(handleError);
|
|
495
481
|
try {
|
|
496
482
|
let actual;
|
|
497
483
|
let previous;
|
|
@@ -538,7 +524,17 @@ class Page extends import_instrumentation.SdkObject {
|
|
|
538
524
|
}
|
|
539
525
|
throw new Error(intermediateResult.errorMessage);
|
|
540
526
|
} catch (e) {
|
|
541
|
-
|
|
527
|
+
if (js.isJavaScriptErrorInEvaluate(e) || (0, import_selectorParser.isInvalidSelectorError)(e))
|
|
528
|
+
throw e;
|
|
529
|
+
let errorMessage = e.message;
|
|
530
|
+
if (e instanceof import_errors.TimeoutError && intermediateResult?.previous)
|
|
531
|
+
errorMessage = `Failed to take two consecutive stable screenshots.`;
|
|
532
|
+
return {
|
|
533
|
+
log: (0, import_callLog.compressCallLog)(e.message ? [...progress.metadata.log, e.message] : progress.metadata.log),
|
|
534
|
+
...intermediateResult,
|
|
535
|
+
errorMessage,
|
|
536
|
+
timedOut: e instanceof import_errors.TimeoutError
|
|
537
|
+
};
|
|
542
538
|
}
|
|
543
539
|
}
|
|
544
540
|
async screenshot(progress, options) {
|
package/lib/server/progress.js
CHANGED
|
@@ -31,17 +31,9 @@ class ProgressController {
|
|
|
31
31
|
this._donePromise = new import_manualPromise.ManualPromise();
|
|
32
32
|
// Cleanups to be run only in the case of abort.
|
|
33
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;
|
|
40
34
|
this._state = "before";
|
|
41
|
-
this._strictMode = !process.env.PLAYWRIGHT_LEGACY_TIMEOUTS;
|
|
42
35
|
this.metadata = metadata;
|
|
43
|
-
this.
|
|
44
|
-
this.instrumentation = sdkObject.instrumentation;
|
|
36
|
+
this._sdkObject = sdkObject;
|
|
45
37
|
this._logName = sdkObject.logName || "api";
|
|
46
38
|
this._forceAbortPromise.catch((e) => null);
|
|
47
39
|
}
|
|
@@ -54,49 +46,21 @@ class ProgressController {
|
|
|
54
46
|
this._state = { error };
|
|
55
47
|
this._forceAbortPromise.reject(error);
|
|
56
48
|
}
|
|
57
|
-
|
|
58
|
-
await this._donePromise;
|
|
49
|
+
await this._donePromise;
|
|
59
50
|
}
|
|
60
51
|
async run(task, timeout) {
|
|
61
52
|
(0, import_utils.assert)(this._state === "before");
|
|
62
53
|
this._state = "running";
|
|
63
|
-
let customErrorHandler;
|
|
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
|
-
timeoutError[kAbortErrorSymbol] = true;
|
|
73
|
-
this._state = { error: timeoutError };
|
|
74
|
-
this._forceAbortPromise.reject(timeoutError);
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
const remaining = deadline - (0, import_utils.monotonicTime)();
|
|
78
|
-
if (remaining <= 0)
|
|
79
|
-
onTimeout();
|
|
80
|
-
else
|
|
81
|
-
timer = setTimeout(onTimeout, remaining);
|
|
82
|
-
};
|
|
83
54
|
const progress = {
|
|
84
55
|
log: (message) => {
|
|
85
56
|
if (this._state === "running")
|
|
86
57
|
this.metadata.log.push(message);
|
|
87
|
-
this.instrumentation.onCallLog(this.
|
|
58
|
+
this._sdkObject.instrumentation.onCallLog(this._sdkObject, this.metadata, this._logName, message);
|
|
88
59
|
},
|
|
89
60
|
cleanupWhenAborted: (cleanup) => {
|
|
90
|
-
if (this.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
this._cleanups.push(cleanup);
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
if (this._state === "running")
|
|
97
|
-
this._cleanups.push(cleanup);
|
|
98
|
-
else
|
|
99
|
-
runCleanup(typeof this._state === "object" ? this._state.error : void 0, cleanup);
|
|
61
|
+
if (this._state !== "running")
|
|
62
|
+
throw new Error("Internal error: cannot register cleanup after operation has finished.");
|
|
63
|
+
this._cleanups.push(cleanup);
|
|
100
64
|
},
|
|
101
65
|
metadata: this.metadata,
|
|
102
66
|
race: (promise) => {
|
|
@@ -116,34 +80,26 @@ class ProgressController {
|
|
|
116
80
|
let timer2;
|
|
117
81
|
const promise = new Promise((f) => timer2 = setTimeout(f, timeout2));
|
|
118
82
|
return progress.race(promise).finally(() => clearTimeout(timer2));
|
|
119
|
-
},
|
|
120
|
-
legacyDisableTimeout: () => {
|
|
121
|
-
if (this._strictMode)
|
|
122
|
-
return;
|
|
123
|
-
clearTimeout(timer);
|
|
124
|
-
},
|
|
125
|
-
legacyEnableTimeout: () => {
|
|
126
|
-
if (this._strictMode)
|
|
127
|
-
return;
|
|
128
|
-
startTimer();
|
|
129
|
-
},
|
|
130
|
-
legacySetErrorHandler: (handler) => {
|
|
131
|
-
if (this._strictMode)
|
|
132
|
-
return;
|
|
133
|
-
customErrorHandler = handler;
|
|
134
83
|
}
|
|
135
84
|
};
|
|
136
|
-
|
|
85
|
+
let timer;
|
|
86
|
+
if (timeout) {
|
|
87
|
+
const timeoutError = new import_errors.TimeoutError(`Timeout ${timeout}ms exceeded.`);
|
|
88
|
+
timer = setTimeout(() => {
|
|
89
|
+
if (this._state === "running") {
|
|
90
|
+
timeoutError[kAbortErrorSymbol] = true;
|
|
91
|
+
this._state = { error: timeoutError };
|
|
92
|
+
this._forceAbortPromise.reject(timeoutError);
|
|
93
|
+
}
|
|
94
|
+
}, timeout);
|
|
95
|
+
}
|
|
137
96
|
try {
|
|
138
|
-
const
|
|
139
|
-
const result = this._strictMode ? await promise : await Promise.race([promise, this._forceAbortPromise]);
|
|
97
|
+
const result = await task(progress);
|
|
140
98
|
this._state = "finished";
|
|
141
99
|
return result;
|
|
142
100
|
} catch (error) {
|
|
143
101
|
this._state = { error };
|
|
144
102
|
await Promise.all(this._cleanups.splice(0).map((cleanup) => runCleanup(error, cleanup)));
|
|
145
|
-
if (customErrorHandler)
|
|
146
|
-
return customErrorHandler(error);
|
|
147
103
|
throw error;
|
|
148
104
|
} finally {
|
|
149
105
|
clearTimeout(timer);
|