playwright-core 1.55.0-alpha-2025-07-29 → 1.55.0-alpha-2025-07-30
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/lib/generated/injectedScriptSource.js +1 -1
- package/lib/generated/pollingRecorderSource.js +1 -1
- package/lib/protocol/validator.js +0 -16
- package/lib/server/android/android.js +54 -43
- package/lib/server/bidi/bidiPage.js +4 -0
- package/lib/server/browser.js +22 -18
- package/lib/server/browserContext.js +73 -46
- package/lib/server/browserType.js +67 -48
- package/lib/server/chromium/chromium.js +34 -28
- package/lib/server/chromium/crCoverage.js +3 -4
- package/lib/server/chromium/videoRecorder.js +10 -19
- package/lib/server/codegen/jsonl.js +2 -1
- package/lib/server/debugController.js +2 -18
- package/lib/server/dispatchers/debugControllerDispatcher.js +0 -9
- package/lib/server/dispatchers/localUtilsDispatcher.js +0 -5
- package/lib/server/frames.js +6 -6
- package/lib/server/localUtils.js +12 -7
- package/lib/server/playwright.js +0 -4
- package/lib/server/progress.js +17 -11
- package/lib/server/recorder/recorderUtils.js +5 -0
- package/lib/server/recorder.js +61 -1
- package/lib/server/socksClientCertificatesInterceptor.js +21 -6
- package/lib/server/utils/processLauncher.js +4 -1
- package/lib/utils/isomorphic/ariaSnapshot.js +58 -4
- package/lib/utils/isomorphic/protocolMetainfo.js +1 -5
- package/lib/utils/isomorphic/urlMatch.js +0 -2
- package/lib/vite/htmlReport/index.html +16 -16
- package/lib/vite/recorder/assets/{codeMirrorModule-cgtwtYOb.js → codeMirrorModule-BAFWw0fz.js} +1 -1
- package/lib/vite/recorder/assets/{index-KWWSfrzB.js → index-DyMqECqY.js} +28 -28
- package/lib/vite/recorder/index.html +1 -1
- package/lib/vite/traceViewer/assets/{codeMirrorModule-k_7BpzGX.js → codeMirrorModule-BOjqK4ng.js} +1 -1
- package/lib/vite/traceViewer/assets/{defaultSettingsView-CKM53V_K.js → defaultSettingsView-B-LNxb2i.js} +103 -103
- package/lib/vite/traceViewer/{index.CCXGYfh2.js → index.CWlPEVCA.js} +1 -1
- package/lib/vite/traceViewer/index.html +2 -2
- package/lib/vite/traceViewer/{uiMode.CNa3x5Xj.js → uiMode.NUAVc1od.js} +1 -1
- package/lib/vite/traceViewer/uiMode.html +2 -2
- package/package.json +1 -1
package/lib/server/frames.js
CHANGED
|
@@ -618,7 +618,7 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
618
618
|
return null;
|
|
619
619
|
return continuePolling;
|
|
620
620
|
}
|
|
621
|
-
const result = await progress.
|
|
621
|
+
const result = await progress.race(resolved.injected.evaluateHandle((injected, { info, root }) => {
|
|
622
622
|
if (root && !root.isConnected)
|
|
623
623
|
throw injected.createStacklessError("Element is not attached to the DOM");
|
|
624
624
|
const elements = injected.querySelectorAll(info.parsed, root || document);
|
|
@@ -633,7 +633,7 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
633
633
|
log2 = ` locator resolved to ${visible2 ? "visible" : "hidden"} ${injected.previewNode(element2)}`;
|
|
634
634
|
}
|
|
635
635
|
return { log: log2, element: element2, visible: visible2, attached: !!element2 };
|
|
636
|
-
}, { info: resolved.info, root: resolved.frame === this ? scope : void 0 })
|
|
636
|
+
}, { info: resolved.info, root: resolved.frame === this ? scope : void 0 }));
|
|
637
637
|
const { log, visible, attached } = await progress.race(result.evaluate((r) => ({ log: r.log, visible: r.visible, attached: r.attached })));
|
|
638
638
|
if (log)
|
|
639
639
|
progress.log(log);
|
|
@@ -898,7 +898,7 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
898
898
|
const resolved = await progress.race(this.selectors.resolveInjectedForSelector(selector, { strict }));
|
|
899
899
|
if (!resolved)
|
|
900
900
|
return continuePolling;
|
|
901
|
-
const result = await progress.
|
|
901
|
+
const result = await progress.race(resolved.injected.evaluateHandle((injected, { info, callId }) => {
|
|
902
902
|
const elements = injected.querySelectorAll(info.parsed, document);
|
|
903
903
|
if (callId)
|
|
904
904
|
injected.markTargetElements(new Set(elements), callId);
|
|
@@ -912,7 +912,7 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
912
912
|
log2 = ` locator resolved to ${injected.previewNode(element2)}`;
|
|
913
913
|
}
|
|
914
914
|
return { log: log2, success: !!element2, element: element2 };
|
|
915
|
-
}, { info: resolved.info, callId: progress.metadata.id })
|
|
915
|
+
}, { info: resolved.info, callId: progress.metadata.id }));
|
|
916
916
|
const { log, success } = await progress.race(result.evaluate((r) => ({ log: r.log, success: r.success })));
|
|
917
917
|
if (log)
|
|
918
918
|
progress.log(log);
|
|
@@ -982,8 +982,8 @@ class Frame extends import_instrumentation.SdkObject {
|
|
|
982
982
|
async blur(progress, selector, options) {
|
|
983
983
|
dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options.strict, true, (handle) => handle._blur(progress)));
|
|
984
984
|
}
|
|
985
|
-
async resolveSelector(progress, selector) {
|
|
986
|
-
const element = await progress.race(this.selectors.query(selector));
|
|
985
|
+
async resolveSelector(progress, selector, options = {}) {
|
|
986
|
+
const element = await progress.race(this.selectors.query(selector, options));
|
|
987
987
|
if (!element)
|
|
988
988
|
throw new Error(`No element matching ${selector}`);
|
|
989
989
|
const generated = await progress.race(element.evaluateInUtility(async ([injected, node]) => {
|
package/lib/server/localUtils.js
CHANGED
|
@@ -135,13 +135,18 @@ async function harOpen(progress, harBackends, params) {
|
|
|
135
135
|
let harBackend;
|
|
136
136
|
if (params.file.endsWith(".zip")) {
|
|
137
137
|
const zipFile = new import_zipFile.ZipFile(params.file);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
138
|
+
try {
|
|
139
|
+
const entryNames = await progress.race(zipFile.entries());
|
|
140
|
+
const harEntryName = entryNames.find((e) => e.endsWith(".har"));
|
|
141
|
+
if (!harEntryName)
|
|
142
|
+
return { error: "Specified archive does not have a .har file" };
|
|
143
|
+
const har = await progress.race(zipFile.read(harEntryName));
|
|
144
|
+
const harFile = JSON.parse(har.toString());
|
|
145
|
+
harBackend = new import_harBackend.HarBackend(harFile, null, zipFile);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
zipFile.close();
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
145
150
|
} else {
|
|
146
151
|
const harFile = JSON.parse(await progress.race(import_fs.default.promises.readFile(params.file, "utf-8")));
|
|
147
152
|
harBackend = new import_harBackend.HarBackend(harFile, import_path.default.dirname(params.file), null);
|
package/lib/server/playwright.js
CHANGED
|
@@ -58,10 +58,6 @@ class Playwright extends import_instrumentation.SdkObject {
|
|
|
58
58
|
this.android = new import_android.Android(this, new import_backendAdb.AdbBackend());
|
|
59
59
|
this.debugController = new import_debugController.DebugController(this);
|
|
60
60
|
}
|
|
61
|
-
async hideHighlight() {
|
|
62
|
-
await Promise.all([...this._allPages].map((p) => p.hideHighlight().catch(() => {
|
|
63
|
-
})));
|
|
64
|
-
}
|
|
65
61
|
allBrowsers() {
|
|
66
62
|
return [...this._allBrowsers];
|
|
67
63
|
}
|
package/lib/server/progress.js
CHANGED
|
@@ -19,7 +19,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
var progress_exports = {};
|
|
20
20
|
__export(progress_exports, {
|
|
21
21
|
ProgressController: () => ProgressController,
|
|
22
|
-
isAbortError: () => isAbortError
|
|
22
|
+
isAbortError: () => isAbortError,
|
|
23
|
+
raceUncancellableOperationWithCleanup: () => raceUncancellableOperationWithCleanup
|
|
23
24
|
});
|
|
24
25
|
module.exports = __toCommonJS(progress_exports);
|
|
25
26
|
var import_errors = require("./errors");
|
|
@@ -67,15 +68,6 @@ class ProgressController {
|
|
|
67
68
|
const promises = Array.isArray(promise) ? promise : [promise];
|
|
68
69
|
return Promise.race([...promises, this._forceAbortPromise]);
|
|
69
70
|
},
|
|
70
|
-
raceWithCleanup: (promise, cleanup) => {
|
|
71
|
-
return progress.race(promise.then((result) => {
|
|
72
|
-
if (this._state !== "running")
|
|
73
|
-
cleanup(result);
|
|
74
|
-
else
|
|
75
|
-
this._cleanups.push(() => cleanup(result));
|
|
76
|
-
return result;
|
|
77
|
-
}));
|
|
78
|
-
},
|
|
79
71
|
wait: async (timeout2) => {
|
|
80
72
|
let timer2;
|
|
81
73
|
const promise = new Promise((f) => timer2 = setTimeout(f, timeout2));
|
|
@@ -117,8 +109,22 @@ const kAbortErrorSymbol = Symbol("kAbortError");
|
|
|
117
109
|
function isAbortError(error) {
|
|
118
110
|
return !!error[kAbortErrorSymbol];
|
|
119
111
|
}
|
|
112
|
+
async function raceUncancellableOperationWithCleanup(progress, run, cleanup) {
|
|
113
|
+
let aborted = false;
|
|
114
|
+
try {
|
|
115
|
+
return await progress.race(run().then(async (t) => {
|
|
116
|
+
if (aborted)
|
|
117
|
+
await cleanup(t);
|
|
118
|
+
return t;
|
|
119
|
+
}));
|
|
120
|
+
} catch (error) {
|
|
121
|
+
aborted = true;
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
120
125
|
// Annotate the CommonJS export names for ESM import in node:
|
|
121
126
|
0 && (module.exports = {
|
|
122
127
|
ProgressController,
|
|
123
|
-
isAbortError
|
|
128
|
+
isAbortError,
|
|
129
|
+
raceUncancellableOperationWithCleanup
|
|
124
130
|
});
|
|
@@ -22,6 +22,7 @@ __export(recorderUtils_exports, {
|
|
|
22
22
|
collapseActions: () => collapseActions,
|
|
23
23
|
frameForAction: () => frameForAction,
|
|
24
24
|
generateFrameSelector: () => generateFrameSelector,
|
|
25
|
+
isAssertAction: () => isAssertAction,
|
|
25
26
|
mainFrameForAction: () => mainFrameForAction,
|
|
26
27
|
metadataToCallLog: () => metadataToCallLog,
|
|
27
28
|
shouldMergeAction: () => shouldMergeAction
|
|
@@ -75,6 +76,9 @@ async function frameForAction(pageAliases, actionInContext, action) {
|
|
|
75
76
|
throw new Error("Internal error: frame not found");
|
|
76
77
|
return result.frame;
|
|
77
78
|
}
|
|
79
|
+
function isAssertAction(action) {
|
|
80
|
+
return action.name.startsWith("assert");
|
|
81
|
+
}
|
|
78
82
|
function isSameAction(a, b) {
|
|
79
83
|
return a.action.name === b.action.name && a.frame.pageAlias === b.frame.pageAlias && a.frame.framePath.join("|") === b.frame.framePath.join("|");
|
|
80
84
|
}
|
|
@@ -151,6 +155,7 @@ async function generateFrameSelectorInParent(parent, frame) {
|
|
|
151
155
|
collapseActions,
|
|
152
156
|
frameForAction,
|
|
153
157
|
generateFrameSelector,
|
|
158
|
+
isAssertAction,
|
|
154
159
|
mainFrameForAction,
|
|
155
160
|
metadataToCallLog,
|
|
156
161
|
shouldMergeAction
|
package/lib/server/recorder.js
CHANGED
|
@@ -48,6 +48,8 @@ var import_utils2 = require("./../utils");
|
|
|
48
48
|
var import_frames = require("./frames");
|
|
49
49
|
var import_page = require("./page");
|
|
50
50
|
var import_recorderRunner = require("./recorder/recorderRunner");
|
|
51
|
+
var import_ariaSnapshot = require("../utils/isomorphic/ariaSnapshot");
|
|
52
|
+
var import_utilsBundle = require("../utilsBundle");
|
|
51
53
|
const recorderSymbol = Symbol("recorderSymbol");
|
|
52
54
|
const RecorderEvent = {
|
|
53
55
|
PausedStateChanged: "pausedStateChanged",
|
|
@@ -440,15 +442,66 @@ class Recorder extends import_events.default {
|
|
|
440
442
|
};
|
|
441
443
|
return actionInContext;
|
|
442
444
|
}
|
|
445
|
+
async _maybeGenerateAssertAction(frame, actionInContext) {
|
|
446
|
+
const lastAction = getLastFrameAction(frame);
|
|
447
|
+
if ((0, import_recorderUtils.isAssertAction)(actionInContext.action))
|
|
448
|
+
return;
|
|
449
|
+
if (lastAction && ((0, import_recorderUtils.isAssertAction)(lastAction.action) || (0, import_recorderUtils.shouldMergeAction)(actionInContext, lastAction)))
|
|
450
|
+
return;
|
|
451
|
+
const newSnapshot = actionInContext.action.ariaSnapshot;
|
|
452
|
+
if (!newSnapshot)
|
|
453
|
+
return;
|
|
454
|
+
const lastSnapshot = lastAction?.action.ariaSnapshot || `- document [ref=e1]
|
|
455
|
+
`;
|
|
456
|
+
if (!lastSnapshot)
|
|
457
|
+
return;
|
|
458
|
+
const callMetadata = (0, import_instrumentation.serverSideCallMetadata)();
|
|
459
|
+
const controller = new import_progress.ProgressController(callMetadata, frame);
|
|
460
|
+
const selector = await controller.run(async (progress) => {
|
|
461
|
+
const ref = (0, import_ariaSnapshot.findNewElementRef)(import_utilsBundle.yaml, lastSnapshot, newSnapshot);
|
|
462
|
+
if (!ref)
|
|
463
|
+
return;
|
|
464
|
+
const { resolvedSelector } = await frame.resolveSelector(progress, `aria-ref=${ref}`, { mainWorld: true }).catch(() => ({ resolvedSelector: void 0 }));
|
|
465
|
+
if (!resolvedSelector)
|
|
466
|
+
return;
|
|
467
|
+
const isVisible = await frame._page.mainFrame().isVisible(progress, resolvedSelector, { strict: true }).catch(() => false);
|
|
468
|
+
return isVisible ? resolvedSelector : void 0;
|
|
469
|
+
}).catch(() => void 0);
|
|
470
|
+
if (!selector)
|
|
471
|
+
return;
|
|
472
|
+
if (!actionInContext.frame.framePath.length && "selector" in actionInContext.action && actionInContext.action.selector === selector)
|
|
473
|
+
return;
|
|
474
|
+
const assertActionInContext = {
|
|
475
|
+
frame: {
|
|
476
|
+
pageGuid: actionInContext.frame.pageGuid,
|
|
477
|
+
pageAlias: actionInContext.frame.pageAlias,
|
|
478
|
+
framePath: []
|
|
479
|
+
},
|
|
480
|
+
action: {
|
|
481
|
+
name: "assertVisible",
|
|
482
|
+
selector,
|
|
483
|
+
signals: []
|
|
484
|
+
},
|
|
485
|
+
startTime: actionInContext.startTime,
|
|
486
|
+
endTime: actionInContext.startTime
|
|
487
|
+
};
|
|
488
|
+
return assertActionInContext;
|
|
489
|
+
}
|
|
443
490
|
async _performAction(frame, action) {
|
|
444
491
|
const actionInContext = await this._createActionInContext(frame, action);
|
|
492
|
+
const assertActionInContext = await this._maybeGenerateAssertAction(frame, actionInContext);
|
|
493
|
+
if (assertActionInContext)
|
|
494
|
+
this._signalProcessor.addAction(assertActionInContext);
|
|
445
495
|
this._signalProcessor.addAction(actionInContext);
|
|
496
|
+
setLastFrameAction(frame, actionInContext);
|
|
446
497
|
if (actionInContext.action.name !== "openPage" && actionInContext.action.name !== "closePage")
|
|
447
498
|
await (0, import_recorderRunner.performAction)(this._pageAliases, actionInContext);
|
|
448
499
|
actionInContext.endTime = (0, import_utils2.monotonicTime)();
|
|
449
500
|
}
|
|
450
501
|
async _recordAction(frame, action) {
|
|
451
|
-
|
|
502
|
+
const actionInContext = await this._createActionInContext(frame, action);
|
|
503
|
+
this._signalProcessor.addAction(actionInContext);
|
|
504
|
+
setLastFrameAction(frame, actionInContext);
|
|
452
505
|
}
|
|
453
506
|
_onFrameNavigated(frame, page) {
|
|
454
507
|
const pageAlias = this._pageAliases.get(page);
|
|
@@ -482,6 +535,13 @@ function languageForFile(file) {
|
|
|
482
535
|
return "csharp";
|
|
483
536
|
return "javascript";
|
|
484
537
|
}
|
|
538
|
+
const kLastFrameActionSymbol = Symbol("lastFrameAction");
|
|
539
|
+
function getLastFrameAction(frame) {
|
|
540
|
+
return frame[kLastFrameActionSymbol];
|
|
541
|
+
}
|
|
542
|
+
function setLastFrameAction(frame, action) {
|
|
543
|
+
frame[kLastFrameActionSymbol] = action;
|
|
544
|
+
}
|
|
485
545
|
// Annotate the CommonJS export names for ESM import in node:
|
|
486
546
|
0 && (module.exports = {
|
|
487
547
|
Recorder,
|
|
@@ -44,6 +44,7 @@ var import_browserContext = require("./browserContext");
|
|
|
44
44
|
var import_network = require("./utils/network");
|
|
45
45
|
var import_debugLogger = require("./utils/debugLogger");
|
|
46
46
|
var import_happyEyeballs = require("./utils/happyEyeballs");
|
|
47
|
+
var import_utilsBundle = require("../utilsBundle");
|
|
47
48
|
let dummyServerTlsOptions = void 0;
|
|
48
49
|
function loadDummyServerCertsIfNeeded() {
|
|
49
50
|
if (dummyServerTlsOptions)
|
|
@@ -97,8 +98,9 @@ class SocksProxyConnection {
|
|
|
97
98
|
};
|
|
98
99
|
}
|
|
99
100
|
async connect() {
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
const proxyAgent = this.socksProxy.getProxyAgent(this.host, this.port);
|
|
102
|
+
if (proxyAgent)
|
|
103
|
+
this.target = await proxyAgent.callback(new import_events.EventEmitter(), { host: rewriteToLocalhostIfNeeded(this.host), port: this.port, secureEndpoint: false });
|
|
102
104
|
else
|
|
103
105
|
this.target = await (0, import_happyEyeballs.createSocket)(rewriteToLocalhostIfNeeded(this.host), this.port);
|
|
104
106
|
this.target.once("close", this._targetCloseEventListener);
|
|
@@ -222,7 +224,7 @@ class ClientCertificatesProxy {
|
|
|
222
224
|
(0, import_browserContext.verifyClientCertificates)(contextOptions.clientCertificates);
|
|
223
225
|
this.alpnCache = new ALPNCache();
|
|
224
226
|
this.ignoreHTTPSErrors = contextOptions.ignoreHTTPSErrors;
|
|
225
|
-
this.
|
|
227
|
+
this._proxy = contextOptions.proxy;
|
|
226
228
|
this._initSecureContexts(contextOptions.clientCertificates);
|
|
227
229
|
this._socksProxy = new import_socksProxy.SocksProxy();
|
|
228
230
|
this._socksProxy.setPattern("*");
|
|
@@ -245,6 +247,14 @@ class ClientCertificatesProxy {
|
|
|
245
247
|
});
|
|
246
248
|
loadDummyServerCertsIfNeeded();
|
|
247
249
|
}
|
|
250
|
+
getProxyAgent(host, port) {
|
|
251
|
+
const proxyFromOptions = (0, import_network.createProxyAgent)(this._proxy);
|
|
252
|
+
if (proxyFromOptions)
|
|
253
|
+
return proxyFromOptions;
|
|
254
|
+
const proxyFromEnv = (0, import_utilsBundle.getProxyForUrl)(`https://${host}:${port}`);
|
|
255
|
+
if (proxyFromEnv)
|
|
256
|
+
return (0, import_network.createProxyAgent)({ server: proxyFromEnv });
|
|
257
|
+
}
|
|
248
258
|
_initSecureContexts(clientCertificates) {
|
|
249
259
|
const origin2certs = /* @__PURE__ */ new Map();
|
|
250
260
|
for (const cert of clientCertificates || []) {
|
|
@@ -262,10 +272,15 @@ class ClientCertificatesProxy {
|
|
|
262
272
|
}
|
|
263
273
|
}
|
|
264
274
|
}
|
|
265
|
-
static async create(contextOptions) {
|
|
275
|
+
static async create(progress, contextOptions) {
|
|
266
276
|
const proxy = new ClientCertificatesProxy(contextOptions);
|
|
267
|
-
|
|
268
|
-
|
|
277
|
+
try {
|
|
278
|
+
await progress.race(proxy._socksProxy.listen(0, "127.0.0.1"));
|
|
279
|
+
return proxy;
|
|
280
|
+
} catch (error) {
|
|
281
|
+
await proxy.close();
|
|
282
|
+
throw error;
|
|
283
|
+
}
|
|
269
284
|
}
|
|
270
285
|
proxySettings() {
|
|
271
286
|
return { server: `socks5://127.0.0.1:${this._socksProxy.port()}` };
|
|
@@ -132,7 +132,10 @@ async function launchProcess(options) {
|
|
|
132
132
|
spawnedProcess.once("error", (error) => {
|
|
133
133
|
failed(new Error("Failed to launch: " + error));
|
|
134
134
|
});
|
|
135
|
-
return failedPromise.then((
|
|
135
|
+
return failedPromise.then(async (error) => {
|
|
136
|
+
await cleanup();
|
|
137
|
+
throw error;
|
|
138
|
+
});
|
|
136
139
|
}
|
|
137
140
|
options.log(`<launched> pid=${spawnedProcess.pid}`);
|
|
138
141
|
const stdout = readline.createInterface({ input: spawnedProcess.stdout });
|
|
@@ -20,13 +20,14 @@ var ariaSnapshot_exports = {};
|
|
|
20
20
|
__export(ariaSnapshot_exports, {
|
|
21
21
|
KeyParser: () => KeyParser,
|
|
22
22
|
ParserError: () => ParserError,
|
|
23
|
+
findNewElementRef: () => findNewElementRef,
|
|
23
24
|
parseAriaSnapshot: () => parseAriaSnapshot,
|
|
24
25
|
parseAriaSnapshotUnsafe: () => parseAriaSnapshotUnsafe,
|
|
25
26
|
valueOrRegex: () => valueOrRegex
|
|
26
27
|
});
|
|
27
28
|
module.exports = __toCommonJS(ariaSnapshot_exports);
|
|
28
|
-
function parseAriaSnapshotUnsafe(yaml, text) {
|
|
29
|
-
const result = parseAriaSnapshot(yaml, text);
|
|
29
|
+
function parseAriaSnapshotUnsafe(yaml, text, options = {}) {
|
|
30
|
+
const result = parseAriaSnapshot(yaml, text, options);
|
|
30
31
|
if (result.errors.length)
|
|
31
32
|
throw new Error(result.errors[0].message);
|
|
32
33
|
return result.fragment;
|
|
@@ -187,7 +188,7 @@ function valueOrRegex(value) {
|
|
|
187
188
|
class KeyParser {
|
|
188
189
|
static parse(text, options, errors) {
|
|
189
190
|
try {
|
|
190
|
-
return new KeyParser(text.value)._parse();
|
|
191
|
+
return new KeyParser(text.value, options)._parse();
|
|
191
192
|
} catch (e) {
|
|
192
193
|
if (e instanceof ParserError) {
|
|
193
194
|
const message = options.prettyErrors === false ? e.message : e.message + ":\n\n" + text.value + "\n" + " ".repeat(e.pos) + "^\n";
|
|
@@ -200,10 +201,11 @@ class KeyParser {
|
|
|
200
201
|
throw e;
|
|
201
202
|
}
|
|
202
203
|
}
|
|
203
|
-
constructor(input) {
|
|
204
|
+
constructor(input, options) {
|
|
204
205
|
this._input = input;
|
|
205
206
|
this._pos = 0;
|
|
206
207
|
this._length = input.length;
|
|
208
|
+
this._options = options;
|
|
207
209
|
}
|
|
208
210
|
_peek() {
|
|
209
211
|
return this._input[this._pos] || "";
|
|
@@ -331,6 +333,10 @@ class KeyParser {
|
|
|
331
333
|
return result;
|
|
332
334
|
}
|
|
333
335
|
_applyAttribute(node, key, value, errorPos) {
|
|
336
|
+
if (this._options.allowRef && key === "ref") {
|
|
337
|
+
node.ref = value;
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
334
340
|
if (key === "checked") {
|
|
335
341
|
this._assert(value === "true" || value === "false" || value === "mixed", 'Value of "checked" attribute must be a boolean or "mixed"', errorPos);
|
|
336
342
|
node.checked = value === "true" ? true : value === "false" ? false : "mixed";
|
|
@@ -366,6 +372,8 @@ class KeyParser {
|
|
|
366
372
|
node.selected = value === "true";
|
|
367
373
|
return;
|
|
368
374
|
}
|
|
375
|
+
if (this._options.allowUnknownAttributes)
|
|
376
|
+
return;
|
|
369
377
|
this._assert(false, `Unsupported attribute [${key}]`, errorPos);
|
|
370
378
|
}
|
|
371
379
|
_assert(value, message, valuePos) {
|
|
@@ -379,10 +387,56 @@ class ParserError extends Error {
|
|
|
379
387
|
this.pos = pos;
|
|
380
388
|
}
|
|
381
389
|
}
|
|
390
|
+
function findNewElementRef(yaml, fromSnapshot, toSnapshot) {
|
|
391
|
+
function fillMap(root, map, position) {
|
|
392
|
+
let size = 1;
|
|
393
|
+
let childPosition = position + size;
|
|
394
|
+
for (const child of root.children || []) {
|
|
395
|
+
if (child.kind === "role") {
|
|
396
|
+
size += fillMap(child, map, childPosition);
|
|
397
|
+
childPosition += size;
|
|
398
|
+
} else {
|
|
399
|
+
size++;
|
|
400
|
+
childPosition++;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (!["none", "presentation", "fragment", "iframe", "generic"].includes(root.role) && typeof root.name === "string" && root.name) {
|
|
404
|
+
let byRole = map.get(root.role);
|
|
405
|
+
if (!byRole) {
|
|
406
|
+
byRole = /* @__PURE__ */ new Map();
|
|
407
|
+
map.set(root.role, byRole);
|
|
408
|
+
}
|
|
409
|
+
const existing = byRole.get(root.name);
|
|
410
|
+
const sizeAndPosition = size * 100 - position;
|
|
411
|
+
if (!existing || existing.sizeAndPosition < sizeAndPosition)
|
|
412
|
+
byRole.set(root.name, { node: root, sizeAndPosition });
|
|
413
|
+
}
|
|
414
|
+
return size;
|
|
415
|
+
}
|
|
416
|
+
const fromMap = /* @__PURE__ */ new Map();
|
|
417
|
+
const from = parseAriaSnapshotUnsafe(yaml, fromSnapshot, { allowRef: true, allowUnknownAttributes: true });
|
|
418
|
+
if (from.kind === "role")
|
|
419
|
+
fillMap(from, fromMap, 0);
|
|
420
|
+
const toMap = /* @__PURE__ */ new Map();
|
|
421
|
+
const to = parseAriaSnapshotUnsafe(yaml, toSnapshot, { allowRef: true, allowUnknownAttributes: true });
|
|
422
|
+
if (to.kind === "role")
|
|
423
|
+
fillMap(to, toMap, 0);
|
|
424
|
+
const result = [];
|
|
425
|
+
for (const [role, byRole] of toMap) {
|
|
426
|
+
for (const [name, byName] of byRole) {
|
|
427
|
+
const inFrom = fromMap.get(role)?.get(name);
|
|
428
|
+
if (!inFrom)
|
|
429
|
+
result.push(byName);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
result.sort((a, b) => b.sizeAndPosition - a.sizeAndPosition);
|
|
433
|
+
return result.find((r) => r.node.ref)?.node.ref;
|
|
434
|
+
}
|
|
382
435
|
// Annotate the CommonJS export names for ESM import in node:
|
|
383
436
|
0 && (module.exports = {
|
|
384
437
|
KeyParser,
|
|
385
438
|
ParserError,
|
|
439
|
+
findNewElementRef,
|
|
386
440
|
parseAriaSnapshot,
|
|
387
441
|
parseAriaSnapshotUnsafe,
|
|
388
442
|
valueOrRegex
|
|
@@ -37,19 +37,15 @@ const methodMetainfo = /* @__PURE__ */ new Map([
|
|
|
37
37
|
["LocalUtils.tracingStarted", { internal: true }],
|
|
38
38
|
["LocalUtils.addStackToTracingNoReply", { internal: true }],
|
|
39
39
|
["LocalUtils.traceDiscarded", { internal: true }],
|
|
40
|
-
["LocalUtils.globToRegex", { internal: true }],
|
|
41
40
|
["Root.initialize", { internal: true }],
|
|
42
41
|
["Playwright.newRequest", { title: "Create request context" }],
|
|
43
42
|
["DebugController.initialize", { internal: true }],
|
|
44
43
|
["DebugController.setReportStateChanged", { internal: true }],
|
|
45
|
-
["DebugController.resetForReuse", { internal: true }],
|
|
46
|
-
["DebugController.navigate", { internal: true }],
|
|
47
44
|
["DebugController.setRecorderMode", { internal: true }],
|
|
48
45
|
["DebugController.highlight", { internal: true }],
|
|
49
46
|
["DebugController.hideHighlight", { internal: true }],
|
|
50
47
|
["DebugController.resume", { internal: true }],
|
|
51
48
|
["DebugController.kill", { internal: true }],
|
|
52
|
-
["DebugController.closeAllBrowsers", { internal: true }],
|
|
53
49
|
["SocksSupport.socksConnected", { internal: true }],
|
|
54
50
|
["SocksSupport.socksFailed", { internal: true }],
|
|
55
51
|
["SocksSupport.socksData", { internal: true }],
|
|
@@ -107,7 +103,7 @@ const methodMetainfo = /* @__PURE__ */ new Map([
|
|
|
107
103
|
["BrowserContext.clockSetFixedTime", { title: 'Set fixed time "{timeNumber}{timeString}"' }],
|
|
108
104
|
["BrowserContext.clockSetSystemTime", { title: 'Set system time "{timeNumber}{timeString}"' }],
|
|
109
105
|
["Page.addInitScript", {}],
|
|
110
|
-
["Page.close", { title: "Close" }],
|
|
106
|
+
["Page.close", { title: "Close page" }],
|
|
111
107
|
["Page.emulateMedia", { title: "Emulate media", snapshot: true }],
|
|
112
108
|
["Page.exposeBinding", { title: "Expose binding" }],
|
|
113
109
|
["Page.goBack", { title: "Go back", slowMo: true, snapshot: true }],
|
|
@@ -20,7 +20,6 @@ var urlMatch_exports = {};
|
|
|
20
20
|
__export(urlMatch_exports, {
|
|
21
21
|
constructURLBasedOnBaseURL: () => constructURLBasedOnBaseURL,
|
|
22
22
|
globToRegexPattern: () => globToRegexPattern,
|
|
23
|
-
resolveGlobToRegexPattern: () => resolveGlobToRegexPattern,
|
|
24
23
|
urlMatches: () => urlMatches,
|
|
25
24
|
urlMatchesEqual: () => urlMatchesEqual
|
|
26
25
|
});
|
|
@@ -162,7 +161,6 @@ function constructURLBasedOnBaseURL(baseURL, givenURL) {
|
|
|
162
161
|
0 && (module.exports = {
|
|
163
162
|
constructURLBasedOnBaseURL,
|
|
164
163
|
globToRegexPattern,
|
|
165
|
-
resolveGlobToRegexPattern,
|
|
166
164
|
urlMatches,
|
|
167
165
|
urlMatchesEqual
|
|
168
166
|
});
|