diff options
Diffstat (limited to 'remote')
337 files changed, 11405 insertions, 8533 deletions
diff --git a/remote/cdp/CDP.sys.mjs b/remote/cdp/CDP.sys.mjs index 0307c71149..cd9aedfecc 100644 --- a/remote/cdp/CDP.sys.mjs +++ b/remote/cdp/CDP.sys.mjs @@ -26,8 +26,6 @@ const RECOMMENDED_PREFS = new Map([ "browser.contentblocking.features.standard", "-tp,tpPrivate,cookieBehavior0,-cm,-fp", ], - // Accept all cookies (see behavior definitions in nsICookieService.idl) - ["network.cookie.cookieBehavior", 0], ]); /** diff --git a/remote/cdp/CDPConnection.sys.mjs b/remote/cdp/CDPConnection.sys.mjs index 1d2eb3e77c..78638899a9 100644 --- a/remote/cdp/CDPConnection.sys.mjs +++ b/remote/cdp/CDPConnection.sys.mjs @@ -40,6 +40,12 @@ export class CDPConnection extends WebSocketConnection { * The session to register. */ registerSession(session) { + lazy.logger.warn( + `Support for the Chrome DevTools Protocol (CDP) in Firefox will be deprecated after Firefox 128 (ESR) ` + + `and will be removed in a later release. CDP users should consider migrating ` + + `to WebDriver BiDi. See https://bugzilla.mozilla.org/show_bug.cgi?id=1872254` + ); + // CDP is not compatible with Fission by default, check the appropriate // preferences are set to ensure compatibility. if ( diff --git a/remote/cdp/Error.sys.mjs b/remote/cdp/Error.sys.mjs index b047285649..37bd33e2e0 100644 --- a/remote/cdp/Error.sys.mjs +++ b/remote/cdp/Error.sys.mjs @@ -44,8 +44,8 @@ export class RemoteAgentError extends Error { * The error must be of this form: * * {"message": "TypeError: foo is not a function\n - * execute@chrome://remote/content/cdp/sessions/Session.jsm:73:39\n - * onMessage@chrome://remote/content/cdp/sessions/TabSession.jsm:65:20"} + * execute@chrome://remote/content/cdp/sessions/Session.sys.mjs:73:39\n + * onMessage@chrome://remote/content/cdp/sessions/TabSession.sys.mjs:65:20"} * * This approach has the notable deficiency that it cannot deal * with causes to errors because of the unstructured nature of CDP diff --git a/remote/cdp/domains/Domain.sys.mjs b/remote/cdp/domains/Domain.sys.mjs index d9b36c62b8..d753c35863 100644 --- a/remote/cdp/domains/Domain.sys.mjs +++ b/remote/cdp/domains/Domain.sys.mjs @@ -29,8 +29,8 @@ export class Domain { /** * Execute the provided method in the child domain that has the same domain - * name. eg. calling this.executeInChild from domains/parent/Input.jsm will - * attempt to execute the method in domains/content/Input.jsm. + * name. eg. calling this.executeInChild from domains/parent/Input.sys.mjs will + * attempt to execute the method in domains/content/Input.sys.mjs. * * This can only be called from parent domains managed by a TabSession. * diff --git a/remote/cdp/domains/content/Runtime.sys.mjs b/remote/cdp/domains/content/Runtime.sys.mjs index 35e0f16710..44c36914d4 100644 --- a/remote/cdp/domains/content/Runtime.sys.mjs +++ b/remote/cdp/domains/content/Runtime.sys.mjs @@ -613,7 +613,7 @@ export class Runtime extends ContentProcessDomain { * @param {nsIConsoleMessage} subject * Console message. */ - observe(subject, topic, data) { + observe(subject) { if (subject instanceof Ci.nsIScriptError && subject.hasException) { let entry = fromScriptError(subject); this._emitExceptionThrown(entry); diff --git a/remote/cdp/domains/parent/Network.sys.mjs b/remote/cdp/domains/parent/Network.sys.mjs index 4d36cf994e..18ce65e0c3 100644 --- a/remote/cdp/domains/parent/Network.sys.mjs +++ b/remote/cdp/domains/parent/Network.sys.mjs @@ -146,12 +146,10 @@ export class Network extends Domain { * * Depending on the backend support, will return detailed cookie information in the cookies field. * - * @param {object} options - * * @returns {Array<Cookie>} * Array of cookie objects. */ - async getAllCookies(options = {}) { + async getAllCookies() { const cookies = []; for (const cookie of Services.cookies.cookies) { cookies.push(_buildCookie(cookie)); diff --git a/remote/cdp/domains/parent/Page.sys.mjs b/remote/cdp/domains/parent/Page.sys.mjs index d050277aff..420f99af39 100644 --- a/remote/cdp/domains/parent/Page.sys.mjs +++ b/remote/cdp/domains/parent/Page.sys.mjs @@ -672,12 +672,8 @@ export class Page extends Domain { * When file chooser interception is enabled, * the native file chooser dialog is not shown. * Instead, a protocol event Page.fileChooserOpened is emitted. - * - * @param {object} options - * @param {boolean=} options.enabled - * Enabled state of file chooser interception. */ - setInterceptFileChooserDialog(options = {}) {} + setInterceptFileChooserDialog() {} _getCurrentHistoryIndex() { const { window } = this.session.target; @@ -719,7 +715,7 @@ export class Page extends Domain { */ _onDialogLoaded(e, data) { const { message, type } = data; - // XXX: We rely on the common-dialog-loaded event (see DialogHandler.jsm) + // XXX: We rely on the common-dialog-loaded event (see DialogHandler.sys.mjs) // which is inconsistent with the name "javascriptDialogOpening". // For correctness we should rely on an event fired _before_ the prompt is // visible, such as DOMWillOpenModalDialog. However the payload of this diff --git a/remote/cdp/observers/ContextObserver.sys.mjs b/remote/cdp/observers/ContextObserver.sys.mjs index d0d6fd1f93..14ad98108f 100644 --- a/remote/cdp/observers/ContextObserver.sys.mjs +++ b/remote/cdp/observers/ContextObserver.sys.mjs @@ -121,7 +121,7 @@ export class ContextObserver { } } - observe(subject, topic, data) { + observe(subject, topic) { switch (topic) { case "document-element-inserted": const window = subject.defaultView; diff --git a/remote/cdp/observers/NetworkObserver.sys.mjs b/remote/cdp/observers/NetworkObserver.sys.mjs index ffd8028ba7..10d5ba4588 100644 --- a/remote/cdp/observers/NetworkObserver.sys.mjs +++ b/remote/cdp/observers/NetworkObserver.sys.mjs @@ -186,7 +186,7 @@ export class NetworkObserver { this._redirectMap.set(newChannel, oldChannel); } - _onRequest(channel, topic) { + _onRequest(channel) { const httpChannel = channel.QueryInterface(Ci.nsIHttpChannel); const loadContext = getLoadContext(httpChannel); const browser = loadContext?.topFrameElement; @@ -242,7 +242,7 @@ export class NetworkObserver { }); } - _onResponse(fromCache, httpChannel, topic) { + _onResponse(fromCache, httpChannel) { const loadContext = getLoadContext(httpChannel); if ( !loadContext || diff --git a/remote/cdp/targets/TabTarget.sys.mjs b/remote/cdp/targets/TabTarget.sys.mjs index a35b0c3f07..016b934cb3 100644 --- a/remote/cdp/targets/TabTarget.sys.mjs +++ b/remote/cdp/targets/TabTarget.sys.mjs @@ -94,7 +94,7 @@ export class TabTarget extends Target { /** @returns {Promise<string|null>} */ get faviconUrl() { - return new Promise((resolve, reject) => { + return new Promise(resolve => { lazy.Favicons.getFaviconURLForPage(this.browser.currentURI, url => { if (url) { resolve(url.spec); @@ -143,7 +143,7 @@ export class TabTarget extends Target { // nsIObserver - observe(subject, topic, data) { + observe(subject) { if (subject === this.mm && subject == "message-manager-disconnect") { // disconnect debugging target if <browser> is disconnected, // otherwise this is just a host process change diff --git a/remote/cdp/targets/Target.sys.mjs b/remote/cdp/targets/Target.sys.mjs index 9264110c37..ee6353983b 100644 --- a/remote/cdp/targets/Target.sys.mjs +++ b/remote/cdp/targets/Target.sys.mjs @@ -21,7 +21,7 @@ export class Target { */ constructor(targetList, sessionClass) { // Save a reference to TargetList instance in order to expose it to: - // domains/parent/Target.jsm + // domains/parent/Target.sys.mjs this.targetList = targetList; // When a new connection is made to this target, diff --git a/remote/cdp/test/browser/browser_httpd.js b/remote/cdp/test/browser/browser_httpd.js index fb74ae8b70..f3d7b6581f 100644 --- a/remote/cdp/test/browser/browser_httpd.js +++ b/remote/cdp/test/browser/browser_httpd.js @@ -188,7 +188,7 @@ add_task(async function json_activate_target({ client, tab }) { is(invalidResponse, "No such target id: does-not-exist"); }); -add_task(async function json_close_target({ CDP, client, tab }) { +add_task(async function json_close_target({ CDP, client }) { const { Target } = client; const { targetInfo, newTab } = await openTab(Target); @@ -224,7 +224,7 @@ add_task(async function json_close_target({ CDP, client, tab }) { target => target.id === targetInfo.targetId ); - ok(afterTarget == null, "New target is gone"); + Assert.equal(afterTarget, null, "New target is gone"); const invalidResponse = await requestJSON("/json/close/does-not-exist", { status: 404, diff --git a/remote/cdp/test/browser/input/doc_events.html b/remote/cdp/test/browser/input/doc_events.html index 74df931233..0cedc82e38 100644 --- a/remote/cdp/test/browser/input/doc_events.html +++ b/remote/cdp/test/browser/input/doc_events.html @@ -133,6 +133,9 @@ <div id="trackPointer" class="block"></div> <div> <h2>KeyReporter</h2> + <!-- Dummy Button is used to ensure pressing Shift+Tab on <input> will make the new focus + - remains in the same document, rather than the Chrome UI. --> + <button>Dummy Button</button> <input type="text" id="keys" size="80"> </div> <div> diff --git a/remote/cdp/test/browser/log/browser_entryAdded.js b/remote/cdp/test/browser/log/browser_entryAdded.js index 1c6ba2e0a8..7eb85a4e49 100644 --- a/remote/cdp/test/browser/log/browser_entryAdded.js +++ b/remote/cdp/test/browser/log/browser_entryAdded.js @@ -100,7 +100,7 @@ add_task(async function eventsForScriptErrorContent({ client }) { is(events[0].lineNumber, 2, "Got expected line number"); }); -async function runEntryAddedTest(client, eventCount, callback, options = {}) { +async function runEntryAddedTest(client, eventCount, callback) { const { Log } = client; const EVENT_ENTRY_ADDED = "Log.entryAdded"; @@ -109,7 +109,7 @@ async function runEntryAddedTest(client, eventCount, callback, options = {}) { history.addRecorder({ event: Log.entryAdded, eventName: EVENT_ENTRY_ADDED, - messageFn: payload => `Received "${EVENT_ENTRY_ADDED}"`, + messageFn: () => `Received "${EVENT_ENTRY_ADDED}"`, }); const timeBefore = Date.now(); diff --git a/remote/cdp/test/browser/network/browser_responseReceived.js b/remote/cdp/test/browser/network/browser_responseReceived.js index 41e854de8a..5319f0eb65 100644 --- a/remote/cdp/test/browser/network/browser_responseReceived.js +++ b/remote/cdp/test/browser/network/browser_responseReceived.js @@ -74,8 +74,9 @@ add_task(async function documentNavigationWithResource({ client }) { "127.0.0.1", "Document response has the expected IP address" ); - ok( - typeof docResponse.response.remotePort == "number", + Assert.equal( + typeof docResponse.response.remotePort, + "number", "Document response has a remotePort" ); } @@ -112,8 +113,9 @@ add_task(async function documentNavigationWithResource({ client }) { docResponse.response.remoteIPAddress, "Script response has same IP address as document response" ); - ok( - typeof scriptResponse.response.remotePort == "number", + Assert.equal( + typeof scriptResponse.response.remotePort, + "number", "Script response has a remotePort" ); } @@ -166,8 +168,9 @@ add_task(async function documentNavigationWithResource({ client }) { "127.0.0.1", "Subdocument response has the expected IP address" ); - ok( - typeof frameDocResponse.response.remotePort == "number", + Assert.equal( + typeof frameDocResponse.response.remotePort, + "number", "Subdocument response has a remotePort" ); } @@ -207,8 +210,9 @@ add_task(async function documentNavigationWithResource({ client }) { docResponse.response.remoteIPAddress, "Script response has same IP address as document response" ); - ok( - typeof frameScriptResponse.response.remotePort == "number", + Assert.equal( + typeof frameScriptResponse.response.remotePort, + "number", "Script response has a remotePort" ); } diff --git a/remote/cdp/test/browser/network/browser_setCacheDisabled.js b/remote/cdp/test/browser/network/browser_setCacheDisabled.js index 4af9f0fc07..a7272bfc54 100644 --- a/remote/cdp/test/browser/network/browser_setCacheDisabled.js +++ b/remote/cdp/test/browser/network/browser_setCacheDisabled.js @@ -18,7 +18,7 @@ add_task(async function cacheEnabledAfterDisabled({ client }) { await waitForLoadFlags(); }); -add_task(async function cacheEnabledByDefault({ Network }) { +add_task(async function cacheEnabledByDefault() { await watchLoadFlags(LOAD_NORMAL, TEST_PAGE); await loadURL(TEST_PAGE); await waitForLoadFlags(); @@ -67,7 +67,7 @@ function watchLoadFlags(flags, url) { ); }, - onStateChange(webProgress, request, flags, status) { + onStateChange(webProgress, request, flags) { // We are checking requests - if there isn't one, ignore it. if (!request) { return; @@ -99,8 +99,9 @@ function watchLoadFlags(flags, url) { if (request.name == this.url && (flags & stopFlags) == stopFlags) { this.docShell.removeProgressListener(this); - ok( - this.requestCount > 1, + Assert.greater( + this.requestCount, + 1, this.url + " saw " + this.requestCount + " requests" ); this.callback(); diff --git a/remote/cdp/test/browser/network/head.js b/remote/cdp/test/browser/network/head.js index 3347e79e0f..2910f1c080 100644 --- a/remote/cdp/test/browser/network/head.js +++ b/remote/cdp/test/browser/network/head.js @@ -47,14 +47,16 @@ function assertEventOrder(first, second, options = {}) { const firstDescription = getDescriptionForEvent(first); const secondDescription = getDescriptionForEvent(second); - ok( - first.index < second.index, + Assert.less( + first.index, + second.index, `${firstDescription} received before ${secondDescription})` ); if (!ignoreTimestamps) { - ok( - first.payload.timestamp <= second.payload.timestamp, + Assert.lessOrEqual( + first.payload.timestamp, + second.payload.timestamp, `Timestamp of ${firstDescription}) is earlier than ${secondDescription})` ); } diff --git a/remote/cdp/test/browser/page/browser_captureScreenshot.js b/remote/cdp/test/browser/page/browser_captureScreenshot.js index ecd688fd14..1ccd54bc36 100644 --- a/remote/cdp/test/browser/page/browser_captureScreenshot.js +++ b/remote/cdp/test/browser/page/browser_captureScreenshot.js @@ -135,12 +135,14 @@ add_task(async function asJPEGFormatAndQuality({ client }) { is(info10.height, (viewport.height - viewport.y) * scale); // Images of different quality result in different content sizes - ok( - info100.length > infoDefault.length, + Assert.greater( + info100.length, + infoDefault.length, "Size of quality 100 is larger than default" ); - ok( - info10.length < infoDefault.length, + Assert.less( + info10.length, + infoDefault.length, "Size of quality 10 is smaller than default" ); }); diff --git a/remote/cdp/test/browser/page/browser_getLayoutMetrics.js b/remote/cdp/test/browser/page/browser_getLayoutMetrics.js index db8b3e8f3c..ad17e97aec 100644 --- a/remote/cdp/test/browser/page/browser_getLayoutMetrics.js +++ b/remote/cdp/test/browser/page/browser_getLayoutMetrics.js @@ -21,12 +21,14 @@ add_task(async function documentSmallerThanViewport({ client }) { layoutViewport.pageY, "Y position of content is equal to layout viewport" ); - ok( - contentSize.width <= layoutViewport.clientWidth, + Assert.lessOrEqual( + contentSize.width, + layoutViewport.clientWidth, "Width of content is smaller than the layout viewport" ); - ok( - contentSize.height <= layoutViewport.clientHeight, + Assert.lessOrEqual( + contentSize.height, + layoutViewport.clientHeight, "Height of content is smaller than the layout viewport" ); }); @@ -49,12 +51,14 @@ add_task(async function documentLargerThanViewport({ client }) { layoutViewport.pageY, "Y position of content is equal to layout viewport" ); - ok( - contentSize.width > layoutViewport.clientWidth, + Assert.greater( + contentSize.width, + layoutViewport.clientWidth, "Width of content is larger than the layout viewport" ); - ok( - contentSize.height > layoutViewport.clientHeight, + Assert.greater( + contentSize.height, + layoutViewport.clientHeight, "Height of content is larger than the layout viewport" ); }); @@ -81,12 +85,14 @@ add_task(async function documentLargerThanViewportScrolledXY({ client }) { contentSize.y + 100, "Y position of content is equal to layout viewport" ); - ok( - contentSize.width > layoutViewport.clientWidth, + Assert.greater( + contentSize.width, + layoutViewport.clientWidth, "Width of content is larger than the layout viewport" ); - ok( - contentSize.height > layoutViewport.clientHeight, + Assert.greater( + contentSize.height, + layoutViewport.clientHeight, "Height of content is larger than the layout viewport" ); }); diff --git a/remote/cdp/test/browser/page/browser_lifecycleEvent.js b/remote/cdp/test/browser/page/browser_lifecycleEvent.js index da5f5da9e8..eecf18f310 100644 --- a/remote/cdp/test/browser/page/browser_lifecycleEvent.js +++ b/remote/cdp/test/browser/page/browser_lifecycleEvent.js @@ -178,9 +178,10 @@ async function runPageLifecycleTest(client, expectedEventSets, callback) { // Check data as exposed by each of these events let lastTimestamp = frameEvents[0].payload.timestamp; - frameEvents.forEach(({ payload }, index) => { - ok( - payload.timestamp >= lastTimestamp, + frameEvents.forEach(({ payload }) => { + Assert.greaterOrEqual( + payload.timestamp, + lastTimestamp, "timestamp succeeds the one from the former event" ); lastTimestamp = payload.timestamp; diff --git a/remote/cdp/test/browser/runtime/browser_exceptionThrown.js b/remote/cdp/test/browser/runtime/browser_exceptionThrown.js index 23e6dc2de9..ad46ae25a9 100644 --- a/remote/cdp/test/browser/runtime/browser_exceptionThrown.js +++ b/remote/cdp/test/browser/runtime/browser_exceptionThrown.js @@ -76,12 +76,7 @@ add_task(async function eventsForScriptErrorWithException({ client }) { is(callFrames[1].url, PAGE_CONSOLE_EVENTS, "Got expected url"); }); -async function runExceptionThrownTest( - client, - eventCount, - callback, - options = {} -) { +async function runExceptionThrownTest(client, eventCount, callback) { const { Runtime } = client; const EVENT_EXCEPTION_THROWN = "Runtime.exceptionThrown"; diff --git a/remote/cdp/test/browser/runtime/browser_getProperties.js b/remote/cdp/test/browser/runtime/browser_getProperties.js index f897c3dfcd..f004480a22 100644 --- a/remote/cdp/test/browser/runtime/browser_getProperties.js +++ b/remote/cdp/test/browser/runtime/browser_getProperties.js @@ -102,7 +102,11 @@ async function testGetPrototypeProperties({ Runtime }, contextId) { objectId: result.objectId, ownProperties: false, }); - ok(result2.length > 1, "We have more properties than just the object one"); + Assert.greater( + result2.length, + 1, + "We have more properties than just the object one" + ); const foo = result2.find(p => p.name == "foo"); ok(foo, "The object property is described"); ok(foo.isOwn, "and is reported as 'own' property"); diff --git a/remote/cdp/test/browser/security/browser_setIgnoreCertificateErrors.js b/remote/cdp/test/browser/security/browser_setIgnoreCertificateErrors.js index d21e737ebe..969541f842 100644 --- a/remote/cdp/test/browser/security/browser_setIgnoreCertificateErrors.js +++ b/remote/cdp/test/browser/security/browser_setIgnoreCertificateErrors.js @@ -68,7 +68,7 @@ function isSecurityState(browser, expectedState) { ); } -add_task(async function testDefault({ Security }) { +add_task(async function testDefault() { for (const url of BAD_CERTS) { info(`Navigating to ${url}`); const loaded = BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser); diff --git a/remote/cdp/test/browser/systemInfo/browser_getProcessInfo.js b/remote/cdp/test/browser/systemInfo/browser_getProcessInfo.js index fb491e248f..d2ee0096e9 100644 --- a/remote/cdp/test/browser/systemInfo/browser_getProcessInfo.js +++ b/remote/cdp/test/browser/systemInfo/browser_getProcessInfo.js @@ -51,9 +51,13 @@ function assertProcesses(processInfo, tabs) { ok(Array.isArray(processInfo), "Process info is an array"); for (const info of processInfo) { - ok(typeof info.id === "number", "Info has a numeric id"); - ok(typeof info.type === "string", "Info has a string type"); - ok(typeof info.cpuTime === "number", "Info has a numeric cpuTime"); + Assert.strictEqual(typeof info.id, "number", "Info has a numeric id"); + Assert.strictEqual(typeof info.type, "string", "Info has a string type"); + Assert.strictEqual( + typeof info.cpuTime, + "number", + "Info has a numeric cpuTime" + ); } const getByType = type => processInfo.filter(info => info.type === type); diff --git a/remote/cdp/test/browser/target/browser_activateTarget.js b/remote/cdp/test/browser/target/browser_activateTarget.js index 03c5a96e07..9f4762dfae 100644 --- a/remote/cdp/test/browser/target/browser_activateTarget.js +++ b/remote/cdp/test/browser/target/browser_activateTarget.js @@ -3,7 +3,7 @@ "use strict"; -add_task(async function raisesWithoutArguments({ client, tab }) { +add_task(async function raisesWithoutArguments({ client }) { const { Target } = client; await Assert.rejects( @@ -13,7 +13,7 @@ add_task(async function raisesWithoutArguments({ client, tab }) { ); }); -add_task(async function raisesWithUnknownTargetId({ client, tab }) { +add_task(async function raisesWithUnknownTargetId({ client }) { const { Target } = client; await Assert.rejects( diff --git a/remote/cdp/test/browser/target/browser_attachToTarget.js b/remote/cdp/test/browser/target/browser_attachToTarget.js index 944d7a9984..2ffebc15a9 100644 --- a/remote/cdp/test/browser/target/browser_attachToTarget.js +++ b/remote/cdp/test/browser/target/browser_attachToTarget.js @@ -3,7 +3,7 @@ "use strict"; -add_task(async function raisesWithoutArguments({ client, tab }) { +add_task(async function raisesWithoutArguments({ client }) { const { Target } = client; await Assert.rejects( @@ -13,7 +13,7 @@ add_task(async function raisesWithoutArguments({ client, tab }) { ); }); -add_task(async function raisesWithUnknownTargetId({ client, tab }) { +add_task(async function raisesWithUnknownTargetId({ client }) { const { Target } = client; await Assert.rejects( diff --git a/remote/cdp/test/browser/target/browser_closeTarget.js b/remote/cdp/test/browser/target/browser_closeTarget.js index 694994148b..b1a980b8e0 100644 --- a/remote/cdp/test/browser/target/browser_closeTarget.js +++ b/remote/cdp/test/browser/target/browser_closeTarget.js @@ -3,7 +3,7 @@ "use strict"; -add_task(async function raisesWithoutArguments({ client, tab }) { +add_task(async function raisesWithoutArguments({ client }) { const { Target } = client; await Assert.rejects( @@ -13,7 +13,7 @@ add_task(async function raisesWithoutArguments({ client, tab }) { ); }); -add_task(async function raisesWithUnknownTargetId({ client, tab }) { +add_task(async function raisesWithUnknownTargetId({ client }) { const { Target } = client; await Assert.rejects( @@ -23,7 +23,7 @@ add_task(async function raisesWithUnknownTargetId({ client, tab }) { ); }); -add_task(async function triggersTargetDestroyed({ client, tab }) { +add_task(async function triggersTargetDestroyed({ client }) { const { Target } = client; const { targetInfo, newTab } = await openTab(Target); diff --git a/remote/cdp/test/browser/target/browser_targetDestroyed.js b/remote/cdp/test/browser/target/browser_targetDestroyed.js index 2ad657b135..6668787ddc 100644 --- a/remote/cdp/test/browser/target/browser_targetDestroyed.js +++ b/remote/cdp/test/browser/target/browser_targetDestroyed.js @@ -3,7 +3,7 @@ "use strict"; -add_task(async function eventFiredWhenTabIsClosed({ client, tab }) { +add_task(async function eventFiredWhenTabIsClosed({ client }) { const { Target } = client; const { newTab } = await openTab(Target); diff --git a/remote/components/RemoteAgent.sys.mjs b/remote/components/RemoteAgent.sys.mjs index c16b8c44b8..4807a8a0e0 100644 --- a/remote/components/RemoteAgent.sys.mjs +++ b/remote/components/RemoteAgent.sys.mjs @@ -9,6 +9,8 @@ ChromeUtils.defineESModuleGetters(lazy, { Deferred: "chrome://remote/content/shared/Sync.sys.mjs", HttpServer: "chrome://remote/content/server/httpd.sys.mjs", Log: "chrome://remote/content/shared/Log.sys.mjs", + RecommendedPreferences: + "chrome://remote/content/shared/RecommendedPreferences.sys.mjs", WebDriverBiDi: "chrome://remote/content/webdriver-bidi/WebDriverBiDi.sys.mjs", }); @@ -31,7 +33,6 @@ const DEFAULT_PORT = 9222; const isRemote = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT; - class RemoteAgentParentProcess { #allowHosts; #allowOrigins; @@ -166,7 +167,7 @@ class RemoteAgentParentProcess { handle(cmdLine) { // remote-debugging-port has to be consumed in nsICommandLineHandler:handle - // to avoid issues on macos. See Marionette.jsm::handle() for more details. + // to avoid issues on macos. See Marionette.sys.mjs::handle() for more details. // TODO: remove after Bug 1724251 is fixed. try { cmdLine.handleFlagWithParam("remote-debugging-port", false); @@ -394,6 +395,9 @@ class RemoteAgentParentProcess { Services.obs.addObserver(this, "mail-idle-startup-tasks-finished"); Services.obs.addObserver(this, "quit-application"); + // Apply the common set of preferences for all supported protocols + lazy.RecommendedPreferences.applyPreferences(); + // With Bug 1717899 we will extend the lifetime of the Remote Agent to // the whole Firefox session, which will be identical to Marionette. For // now prevent logging if the component is not enabled during startup. @@ -484,12 +488,6 @@ class RemoteAgentParentProcess { } class RemoteAgentContentProcess { - #classID; - - constructor() { - this.#classID = Components.ID("{8f685a9d-8181-46d6-a71d-869289099c6d}"); - } - get running() { let reply = Services.cpmm.sendSyncMessage("RemoteAgent:IsRunning"); if (!reply.length) { diff --git a/remote/components/nsIRemoteAgent.idl b/remote/components/nsIRemoteAgent.idl index 89d637bed2..173be75a6e 100644 --- a/remote/components/nsIRemoteAgent.idl +++ b/remote/components/nsIRemoteAgent.idl @@ -30,7 +30,4 @@ interface nsIRemoteAgent : nsISupports %{C++ #define NS_REMOTEAGENT_CONTRACTID "@mozilla.org/remote/agent;1" -#define NS_REMOTEAGENT_CID \ - { 0x8f685a9d, 0x8181, 0x46d6, \ - { 0xa7, 0x1d, x86, x92, x89, x09, x9c, x6d } } %} diff --git a/remote/doc/Building.md b/remote/doc/Building.md index b8ddf5db8d..210510cc14 100644 --- a/remote/doc/Building.md +++ b/remote/doc/Building.md @@ -29,7 +29,7 @@ do this, provided you haven’t touched any compiled code (C++ or Rust): Component files include the likes of components.conf, RemoteAgent.manifest, moz.build files, and jar.mn. -All the JS modules (files ending with `.jsm`) are symlinked into +All the JS modules (files ending with `.sys.mjs`) are symlinked into the build and can be changed without rebuilding. You may also opt out of building all the WebDriver specific components diff --git a/remote/doc/cdp/Architecture.md b/remote/doc/cdp/Architecture.md index bda4956f84..ad6e18eadf 100644 --- a/remote/doc/cdp/Architecture.md +++ b/remote/doc/cdp/Architecture.md @@ -84,7 +84,7 @@ When a request is made to a target URL, `cdp/targets/Target:handle` is called an From a given connection you can know about the other potential targets. You typically do that via `Target.setDiscoverTargets()`, which will emit `Target.targetCreated` events providing a target ID. You may create a new session for the new target by handing the ID to `Target.attachToTarget()`, which will return a session ID. -"Target" here is a reference to the CDP Domain implemented in `cdp/domains/parent/Target.jsm`. That is different from `cdp/targets/Target` +"Target" here is a reference to the CDP Domain implemented in `cdp/domains/parent/Target.sys.mjs`. That is different from `cdp/targets/Target` class which is an implementation detail of the Remote Agent. Then, there is two ways to communicate with the other targets: diff --git a/remote/doc/marionette/CodeStyle.md b/remote/doc/marionette/CodeStyle.md index 0658018a46..19c7ff716d 100644 --- a/remote/doc/marionette/CodeStyle.md +++ b/remote/doc/marionette/CodeStyle.md @@ -21,15 +21,14 @@ Marionette is written in JavaScript and ships as part of Firefox. We have access to all the latest ECMAScript features currently in development, usually before it ships in the wild and we try to make use of new features when appropriate, -especially when they move us off legacy internal replacements -(such as Promise.jsm and Task.jsm). +especially when they move us off legacy internal replacements. One of the peculiarities of working on JavaScript code that ships as part of a runtime platform is, that unlike in a regular web document, we share a single global state with the rest of Firefox. This means we have to be responsible and not leak resources unnecessarily. -JS code in Gecko is organised into _modules_ carrying _.js_ or _.jsm_ +JS code in Gecko is organised into _modules_ carrying _.js_ or _.sys.mjs_ file extensions. Depending on the area of Gecko you’re working on, you may find they have different techniques for exporting symbols, varying indentation and code style, as well as varying linting @@ -178,7 +177,7 @@ The practical details of working on the Marionette code is outlined in [Contributing.md], but generally you do not have to re-build Firefox when changing code. Any change to remote/marionette/*.js will be picked up on restarting Firefox. The only notable exception -is remote/components/Marionette.jsm, which does require +is remote/components/Marionette.sys.mjs, which does require a re-build. [strict mode]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Strict_mode diff --git a/remote/jar.mn b/remote/jar.mn index 4c0ae791b0..7d08451a6f 100644 --- a/remote/jar.mn +++ b/remote/jar.mn @@ -73,6 +73,7 @@ remote.jar: content/shared/webdriver/Assert.sys.mjs (shared/webdriver/Assert.sys.mjs) content/shared/webdriver/Capabilities.sys.mjs (shared/webdriver/Capabilities.sys.mjs) content/shared/webdriver/Errors.sys.mjs (shared/webdriver/Errors.sys.mjs) + content/shared/webdriver/Event.sys.mjs (shared/webdriver/Event.sys.mjs) content/shared/webdriver/KeyData.sys.mjs (shared/webdriver/KeyData.sys.mjs) content/shared/webdriver/NodeCache.sys.mjs (shared/webdriver/NodeCache.sys.mjs) content/shared/webdriver/Session.sys.mjs (shared/webdriver/Session.sys.mjs) diff --git a/remote/mach_commands.py b/remote/mach_commands.py index abf5615ce0..797f313dda 100644 --- a/remote/mach_commands.py +++ b/remote/mach_commands.py @@ -140,6 +140,14 @@ def vendor_puppeteer(command_context, repository, commitish, install): } run_npm( + "run", + "clean", + cwd=puppeteer_dir, + env=env, + exit_on_fail=False, + ) + + run_npm( "install", cwd=os.path.join(command_context.topsrcdir, puppeteer_dir), env=env, @@ -398,7 +406,7 @@ class PuppeteerRunner(MozbuildObject): """ setup() - binary = params.get("binary") or self.get_binary_path() + binary = params.get("binary") headless = params.get("headless", False) product = params.get("product", "firefox") with_cdp = params.get("cdp", False) @@ -432,10 +440,12 @@ class PuppeteerRunner(MozbuildObject): } if product == "firefox": - env["BINARY"] = binary + env["BINARY"] = binary or self.get_binary_path() env["PUPPETEER_PRODUCT"] = "firefox" env["MOZ_WEBRENDER"] = "%d" % params.get("enable_webrender", False) else: + if binary: + env["BINARY"] = binary env["PUPPETEER_CACHE_DIR"] = os.path.join( self.topobjdir, "_tests", @@ -727,6 +737,7 @@ def install_puppeteer(command_context, product, ci): puppeteer_test_dir = os.path.join(puppeteer_dir, "test") if product == "chrome": + env["PUPPETEER_PRODUCT"] = "chrome" env["PUPPETEER_CACHE_DIR"] = os.path.join( command_context.topobjdir, "_tests", puppeteer_dir, ".cache" ) @@ -744,6 +755,8 @@ def install_puppeteer(command_context, product, ci): # Always use the `ci` command to not get updated sub-dependencies installed. run_npm("ci", cwd=puppeteer_dir_full_path, env=env) + + # Build Puppeteer and the code to download browsers. run_npm( "run", "build", @@ -751,6 +764,9 @@ def install_puppeteer(command_context, product, ci): env=env, ) + # Run post install steps, including downloading the Chrome browser if requested + run_npm("run", "postinstall", cwd=puppeteer_dir_full_path, env=env) + def exit(code, error=None): if error is not None: diff --git a/remote/marionette/addon.sys.mjs b/remote/marionette/addon.sys.mjs index f83671694b..5d7169444c 100644 --- a/remote/marionette/addon.sys.mjs +++ b/remote/marionette/addon.sys.mjs @@ -37,7 +37,7 @@ async function installAddon(file) { throw new lazy.error.UnknownError(ERRORS[install.error]); } - return install.install().catch(err => { + return install.install().catch(() => { throw new lazy.error.UnknownError(ERRORS[install.error]); }); } diff --git a/remote/marionette/browser.sys.mjs b/remote/marionette/browser.sys.mjs index fd5aac21a3..d9a867fac5 100644 --- a/remote/marionette/browser.sys.mjs +++ b/remote/marionette/browser.sys.mjs @@ -324,11 +324,8 @@ browser.Context = class { * Registers a new frame, and sets its current frame id to this frame * if it is not already assigned, and if a) we already have a session * or b) we're starting a new session and it is the right start frame. - * - * @param {XULBrowser} target - * The <xul:browser> that was the target of the originating message. */ - register(target) { + register() { if (!this.tabBrowser) { return; } diff --git a/remote/marionette/driver.sys.mjs b/remote/marionette/driver.sys.mjs index 154d2cde83..f4642e756e 100644 --- a/remote/marionette/driver.sys.mjs +++ b/remote/marionette/driver.sys.mjs @@ -540,7 +540,7 @@ GeckoDriver.prototype.handleEvent = function ({ target, type }) { } }; -GeckoDriver.prototype.observe = async function (subject, topic, data) { +GeckoDriver.prototype.observe = async function (subject, topic) { switch (topic) { case TOPIC_BROWSER_READY: this.registerWindow(subject); diff --git a/remote/marionette/interaction.sys.mjs b/remote/marionette/interaction.sys.mjs index c71149a96a..d710f2eb46 100644 --- a/remote/marionette/interaction.sys.mjs +++ b/remote/marionette/interaction.sys.mjs @@ -13,7 +13,7 @@ ChromeUtils.defineESModuleGetters(lazy, { atom: "chrome://remote/content/marionette/atom.sys.mjs", dom: "chrome://remote/content/shared/DOM.sys.mjs", error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs", - event: "chrome://remote/content/marionette/event.sys.mjs", + event: "chrome://remote/content/shared/webdriver/Event.sys.mjs", Log: "chrome://remote/content/shared/Log.sys.mjs", pprint: "chrome://remote/content/shared/Format.sys.mjs", TimedPromise: "chrome://remote/content/marionette/sync.sys.mjs", diff --git a/remote/marionette/jar.mn b/remote/marionette/jar.mn index b206dc2487..21c37ee455 100644 --- a/remote/marionette/jar.mn +++ b/remote/marionette/jar.mn @@ -18,7 +18,6 @@ remote.jar: content/marionette/cookie.sys.mjs (cookie.sys.mjs) content/marionette/driver.sys.mjs (driver.sys.mjs) content/marionette/evaluate.sys.mjs (evaluate.sys.mjs) - content/marionette/event.sys.mjs (event.sys.mjs) content/marionette/interaction.sys.mjs (interaction.sys.mjs) content/marionette/json.sys.mjs (json.sys.mjs) content/marionette/l10n.sys.mjs (l10n.sys.mjs) diff --git a/remote/marionette/navigate.sys.mjs b/remote/marionette/navigate.sys.mjs index 993ca75cf8..31774c9e73 100644 --- a/remote/marionette/navigate.sys.mjs +++ b/remote/marionette/navigate.sys.mjs @@ -265,7 +265,7 @@ navigate.waitForNavigationCompleted = async function waitForNavigationCompleted( checkDone({ finished: true }); }; - const onTimer = timer => { + const onTimer = () => { // For the command "Element Click" we want to detect a potential navigation // as early as possible. The `beforeunload` event is an indication for that // but could still cause the navigation to get aborted by the user. As such @@ -356,7 +356,7 @@ navigate.waitForNavigationCompleted = async function waitForNavigationCompleted( } }; - const onUnload = event => { + const onUnload = () => { lazy.logger.trace( "Canceled page load listener " + "because the top-browsing context has been closed" diff --git a/remote/marionette/prefs.sys.mjs b/remote/marionette/prefs.sys.mjs index 17df13d0fd..d3b995634e 100644 --- a/remote/marionette/prefs.sys.mjs +++ b/remote/marionette/prefs.sys.mjs @@ -171,5 +171,5 @@ export class EnvironmentPrefs { } // There is a future potential of exposing this as Marionette.prefs.port -// if we introduce a Marionette.jsm module. +// if we introduce a Marionette.sys.mjs module. export const MarionettePrefs = new MarionetteBranch(); diff --git a/remote/marionette/reftest-content.js b/remote/marionette/reftest-content.js index 3c0712f232..00be2a73f0 100644 --- a/remote/marionette/reftest-content.js +++ b/remote/marionette/reftest-content.js @@ -30,26 +30,19 @@ BrowserDOMWindow.prototype = { return null; }, - createContentWindow( - aURI, - aOpenWindowInfo, - aWhere, - aFlags, - aTriggeringPrincipal, - aCsp - ) { + createContentWindow(aURI, aOpenWindowInfo, aWhere) { return this._maybeOpen(aOpenWindowInfo, aWhere)?.browsingContext; }, - openURI(aURI, aOpenWindowInfo, aWhere, aFlags, aTriggeringPrincipal, aCsp) { + openURI(aURI, aOpenWindowInfo, aWhere) { return this._maybeOpen(aOpenWindowInfo, aWhere)?.browsingContext; }, - createContentWindowInFrame(aURI, aParams, aWhere, aFlags, aName) { + createContentWindowInFrame(aURI, aParams, aWhere) { return this._maybeOpen(aParams.openWindowInfo, aWhere); }, - openURIInFrame(aURI, aParams, aWhere, aFlags, aName) { + openURIInFrame(aURI, aParams, aWhere) { return this._maybeOpen(aParams.openWindowInfo, aWhere); }, diff --git a/remote/marionette/test/xpcshell/test_cookie.js b/remote/marionette/test/xpcshell/test_cookie.js index b5ce5e9008..496aafd68b 100644 --- a/remote/marionette/test/xpcshell/test_cookie.js +++ b/remote/marionette/test/xpcshell/test_cookie.js @@ -239,7 +239,10 @@ add_task(function test_add() { equal("value", cookie.manager.cookies[0].value); equal(".domain", cookie.manager.cookies[0].host); equal("/", cookie.manager.cookies[0].path); - ok(cookie.manager.cookies[0].expiry > new Date(Date.now()).getTime() / 1000); + Assert.greater( + cookie.manager.cookies[0].expiry, + new Date(Date.now()).getTime() / 1000 + ); cookie.add({ name: "name2", diff --git a/remote/marionette/test/xpcshell/test_sync.js b/remote/marionette/test/xpcshell/test_sync.js index 87ec44e960..19969f4473 100644 --- a/remote/marionette/test/xpcshell/test_sync.js +++ b/remote/marionette/test/xpcshell/test_sync.js @@ -28,7 +28,7 @@ class MessageManager { this.message = message; } - removeMessageListener(message) { + removeMessageListener() { this.func = null; this.message = null; } @@ -55,7 +55,7 @@ class MockTimer { this.cancelled = false; } - initWithCallback(cb, timeout, type) { + initWithCallback(cb) { this.ticks++; if (this.ticks >= this.goal) { cb(); @@ -216,7 +216,7 @@ add_task(function test_TimedPromise_timeoutTypes() { add_task(async function test_TimedPromise_errorMessage() { try { - await new TimedPromise(resolve => {}, { timeout: 0 }); + await new TimedPromise(() => {}, { timeout: 0 }); ok(false, "Expected Timeout error not raised"); } catch (e) { ok( @@ -226,7 +226,7 @@ add_task(async function test_TimedPromise_errorMessage() { } try { - await new TimedPromise(resolve => {}, { + await new TimedPromise(() => {}, { errorMessage: "Not found", timeout: 0, }); diff --git a/remote/server/WebSocketHandshake.sys.mjs b/remote/server/WebSocketHandshake.sys.mjs index f137b484ae..bf9f5d39e9 100644 --- a/remote/server/WebSocketHandshake.sys.mjs +++ b/remote/server/WebSocketHandshake.sys.mjs @@ -68,7 +68,7 @@ function writeString(output, data) { } output.asyncWait( - stream => { + () => { try { const written = output.write(data, data.length); data = data.slice(written); diff --git a/remote/shared/AppInfo.sys.mjs b/remote/shared/AppInfo.sys.mjs index 9e354503ef..16db0191de 100644 --- a/remote/shared/AppInfo.sys.mjs +++ b/remote/shared/AppInfo.sys.mjs @@ -24,7 +24,7 @@ const ID_THUNDERBIRD = "{3550f703-e582-4d05-9a08-453d09bdfdc6}"; export const AppInfo = new Proxy( {}, { - get(target, prop, receiver) { + get(target, prop) { if (target.hasOwnProperty(prop)) { return target[prop]; } diff --git a/remote/shared/RecommendedPreferences.sys.mjs b/remote/shared/RecommendedPreferences.sys.mjs index d0a7739e52..b52057ee2b 100644 --- a/remote/shared/RecommendedPreferences.sys.mjs +++ b/remote/shared/RecommendedPreferences.sys.mjs @@ -145,6 +145,9 @@ const COMMON_PREFERENCES = new Map([ // Do not redirect user when a milstone upgrade of Firefox is detected ["browser.startup.homepage_override.mstone", "ignore"], + // Unload the previously selected tab immediately + ["browser.tabs.remote.unloadDelayMs", 0], + // Don't unload tabs when available memory is running low ["browser.tabs.unloadOnLowMemory", false], @@ -310,6 +313,9 @@ const COMMON_PREFERENCES = new Map([ // Privacy and Tracking Protection ["privacy.trackingprotection.enabled", false], + // Used to check if recommended preferences are applied + ["remote.prefs.recommended.applied", true], + // Don't do network connections for mitm priming ["security.certerrors.mitm.priming.enabled", false], @@ -362,7 +368,7 @@ export const RecommendedPreferences = { * @param {Map<string, object>=} preferences * Map of preference name to preference value. */ - applyPreferences(preferences) { + applyPreferences(preferences = new Map()) { if (!lazy.useRecommendedPrefs) { // If remote.prefs.recommended is set to false, do not set any preference // here. Needed for our Firefox CI. @@ -374,11 +380,7 @@ export const RecommendedPreferences = { if (!this.isInitialized) { // Merge common preferences and optionally provided preferences in a // single map. Hereby the extra preferences have higher priority. - if (preferences) { - preferences = new Map([...COMMON_PREFERENCES, ...preferences]); - } else { - preferences = COMMON_PREFERENCES; - } + preferences = new Map([...COMMON_PREFERENCES, ...preferences]); Services.obs.addObserver(this, "quit-application"); this.isInitialized = true; diff --git a/remote/shared/WebSocketConnection.sys.mjs b/remote/shared/WebSocketConnection.sys.mjs index c9ef050dc5..57b533fffb 100644 --- a/remote/shared/WebSocketConnection.sys.mjs +++ b/remote/shared/WebSocketConnection.sys.mjs @@ -85,11 +85,8 @@ export class WebSocketConnection { * Register a new Session to forward the messages to. * * Needs to be implemented in the sub class. - * - * @param {Session} session - * The session to register. */ - registerSession(session) { + registerSession() { throw new Error("Not implemented"); } @@ -140,7 +137,7 @@ export class WebSocketConnection { /** * Called by the `transport` when the connection is closed. */ - onConnectionClose(status) { + onConnectionClose() { lazy.logger.debug(`${this.constructor.name} ${this.id} closed`); } diff --git a/remote/shared/js-window-actors/NavigationListenerChild.sys.mjs b/remote/shared/js-window-actors/NavigationListenerChild.sys.mjs index a2cd8ccf10..728d9b6e8c 100644 --- a/remote/shared/js-window-actors/NavigationListenerChild.sys.mjs +++ b/remote/shared/js-window-actors/NavigationListenerChild.sys.mjs @@ -56,12 +56,12 @@ export class NavigationListenerChild extends JSWindowActorChild { /** * See note above */ - handleEvent(event) {} + handleEvent() {} /** * See note above */ - receiveMessage(message) {} + receiveMessage() {} /** * A browsing context might be replaced before reaching the parent process, diff --git a/remote/shared/listeners/ContextualIdentityListener.sys.mjs b/remote/shared/listeners/ContextualIdentityListener.sys.mjs index d93b44ed77..42954d223c 100644 --- a/remote/shared/listeners/ContextualIdentityListener.sys.mjs +++ b/remote/shared/listeners/ContextualIdentityListener.sys.mjs @@ -49,7 +49,7 @@ export class ContextualIdentityListener { this.stopListening(); } - observe(subject, topic, data) { + observe(subject, topic) { switch (topic) { case OBSERVER_TOPIC_CREATED: this.emit("created", { identity: subject.wrappedJSObject }); diff --git a/remote/shared/listeners/NetworkEventRecord.sys.mjs b/remote/shared/listeners/NetworkEventRecord.sys.mjs index a41f3edd7d..72b43e3de1 100644 --- a/remote/shared/listeners/NetworkEventRecord.sys.mjs +++ b/remote/shared/listeners/NetworkEventRecord.sys.mjs @@ -163,13 +163,8 @@ export class NetworkEventRecord { * Required API for a NetworkObserver event owner. * * Not used for RemoteAgent. - * - * @param {object} info - * The object containing security information. - * @param {boolean} isRacing - * True if the corresponding channel raced the cache and network requests. */ - addSecurityInfo(info, isRacing) {} + addSecurityInfo() {} /** * Add network event timings. @@ -177,15 +172,8 @@ export class NetworkEventRecord { * Required API for a NetworkObserver event owner. * * Not used for RemoteAgent. - * - * @param {number} total - * The total time for the request. - * @param {object} timings - * The har-like timings. - * @param {object} offsets - * The har-like timings, but as offset from the request start. */ - addEventTimings(total, timings, offsets) {} + addEventTimings() {} /** * Add response cache entry. @@ -193,11 +181,8 @@ export class NetworkEventRecord { * Required API for a NetworkObserver event owner. * * Not used for RemoteAgent. - * - * @param {object} options - * An object which contains a single responseCache property. */ - addResponseCache(options) {} + addResponseCache() {} /** * Add response content. @@ -233,11 +218,8 @@ export class NetworkEventRecord { * Required API for a NetworkObserver event owner. * * Not used for RemoteAgent. - * - * @param {Array} serverTimings - * The server timings. */ - addServerTimings(serverTimings) {} + addServerTimings() {} /** * Add service worker timings. @@ -245,11 +227,8 @@ export class NetworkEventRecord { * Required API for a NetworkObserver event owner. * * Not used for RemoteAgent. - * - * @param {object} serviceWorkerTimings - * The server timings. */ - addServiceWorkerTimings(serviceWorkerTimings) {} + addServiceWorkerTimings() {} onAuthPrompt(authDetails, authCallbacks) { this.#emitAuthRequired(authCallbacks); diff --git a/remote/shared/listeners/test/browser/browser_NetworkListener.js b/remote/shared/listeners/test/browser/browser_NetworkListener.js index 78865f6b80..cc1b42f2fc 100644 --- a/remote/shared/listeners/test/browser/browser_NetworkListener.js +++ b/remote/shared/listeners/test/browser/browser_NetworkListener.js @@ -32,22 +32,22 @@ add_task(async function test_beforeRequestSent() { listener.startListening(); await fetch(tab1.linkedBrowser, "https://example.com/?1"); - ok(events.length == 1, "One event was received"); + Assert.equal(events.length, 1, "One event was received"); assertNetworkEvent(events[0], contextId1, "https://example.com/?1"); info("Check that events are no longer emitted after calling stopListening"); listener.stopListening(); await fetch(tab1.linkedBrowser, "https://example.com/?2"); - ok(events.length == 1, "No new event was received"); + Assert.equal(events.length, 1, "No new event was received"); listener.startListening(); await fetch(tab1.linkedBrowser, "https://example.com/?3"); - ok(events.length == 2, "A new event was received"); + Assert.equal(events.length, 2, "A new event was received"); assertNetworkEvent(events[1], contextId1, "https://example.com/?3"); info("Check network event from the new tab"); await fetch(tab2.linkedBrowser, "https://example.com/?4"); - ok(events.length == 3, "A new event was received"); + Assert.equal(events.length, 3, "A new event was received"); assertNetworkEvent(events[2], contextId2, "https://example.com/?4"); gBrowser.removeTab(tab1); diff --git a/remote/shared/listeners/test/browser/browser_PromptListener.js b/remote/shared/listeners/test/browser/browser_PromptListener.js index 0d3f23db3f..30503ef4fa 100644 --- a/remote/shared/listeners/test/browser/browser_PromptListener.js +++ b/remote/shared/listeners/test/browser/browser_PromptListener.js @@ -156,7 +156,7 @@ add_task(async function test_events_in_another_browser() { await createScriptNode(`setTimeout(() => window.confirm('test'))`); const dialogWin = await dialogPromise; - ok(events.length === 0, "No event was received"); + Assert.strictEqual(events.length, 0, "No event was received"); dialogWin.document.querySelector("dialog").acceptDialog(); @@ -166,7 +166,7 @@ add_task(async function test_events_in_another_browser() { setTimeout(resolve, 500); }); - ok(events.length === 0, "No event was received"); + Assert.strictEqual(events.length, 0, "No event was received"); listener.destroy(); await BrowserTestUtils.closeWindow(win); diff --git a/remote/shared/messagehandler/MessageHandler.sys.mjs b/remote/shared/messagehandler/MessageHandler.sys.mjs index 18ec6b820c..61c8b5c40e 100644 --- a/remote/shared/messagehandler/MessageHandler.sys.mjs +++ b/remote/shared/messagehandler/MessageHandler.sys.mjs @@ -215,7 +215,7 @@ export class MessageHandler extends EventEmitter { /** * Retrieve all module classes matching the moduleName and destination. - * See `getAllModuleClasses` (ModuleCache.jsm) for more details. + * See `getAllModuleClasses` (ModuleCache.sys.mjs) for more details. * * @param {string} moduleName * The name of the module. @@ -267,11 +267,8 @@ export class MessageHandler extends EventEmitter { * provided to this MessageHandler on startup. Implementation is specific to each MessageHandler class. * * By default the implementation is a no-op. - * - * @param {Array<SessionDataItem>} sessionDataItems - * Initial session data items for this MessageHandler. */ - async initialize(sessionDataItems) {} + async initialize() {} /** * Returns the module path corresponding to this MessageHandler class. @@ -297,7 +294,7 @@ export class MessageHandler extends EventEmitter { * * Needs to be implemented in the sub class. */ - static getIdFromContext(context) { + static getIdFromContext() { throw new Error("Not implemented"); } @@ -306,7 +303,7 @@ export class MessageHandler extends EventEmitter { * * Needs to be implemented in the sub class. */ - forwardCommand(command) { + forwardCommand() { throw new Error("Not implemented"); } @@ -316,7 +313,7 @@ export class MessageHandler extends EventEmitter { * * Needs to be implemented in the sub class. */ - matchesContext(contextDescriptor) { + matchesContext() { throw new Error("Not implemented"); } diff --git a/remote/shared/messagehandler/Module.sys.mjs b/remote/shared/messagehandler/Module.sys.mjs index 30b26938e2..c526c7ce6c 100644 --- a/remote/shared/messagehandler/Module.sys.mjs +++ b/remote/shared/messagehandler/Module.sys.mjs @@ -61,12 +61,12 @@ export class Module { * * @param {string} name * Name of the event. - * @param {object} payload + * @param {object} _payload * The event's payload. * @returns {object} * The modified event payload. */ - interceptEvent(name, payload) { + interceptEvent(name, _payload) { throw new Error( `Could not intercept event ${name}, interceptEvent is not implemented in windowglobal-in-root module` ); diff --git a/remote/shared/messagehandler/RootMessageHandler.sys.mjs b/remote/shared/messagehandler/RootMessageHandler.sys.mjs index 06a8cd6f18..ce571c3c12 100644 --- a/remote/shared/messagehandler/RootMessageHandler.sys.mjs +++ b/remote/shared/messagehandler/RootMessageHandler.sys.mjs @@ -51,7 +51,7 @@ export class RootMessageHandler extends MessageHandler { * The ROOT MessageHandler is unique for a given MessageHandler network * (ie for a given sessionId). Reuse the type as context id here. */ - static getIdFromContext(context) { + static getIdFromContext() { return RootMessageHandler.type; } diff --git a/remote/shared/messagehandler/sessiondata/SessionDataReader.sys.mjs b/remote/shared/messagehandler/sessiondata/SessionDataReader.sys.mjs index 6d5ea08e59..f7c91e6bbf 100644 --- a/remote/shared/messagehandler/sessiondata/SessionDataReader.sys.mjs +++ b/remote/shared/messagehandler/sessiondata/SessionDataReader.sys.mjs @@ -18,7 +18,7 @@ ChromeUtils.defineLazyGetter(lazy, "sharedData", () => { /** * Returns a snapshot of the session data map, which is cloned from the - * sessionDataMap singleton of SessionData.jsm. + * sessionDataMap singleton of SessionData.sys.mjs. * * @returns {Map.<string, Array<SessionDataItem>>} * Map of session id to arrays of SessionDataItems. diff --git a/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/retry.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/retry.sys.mjs index f7b2279018..3022744e7c 100644 --- a/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/retry.sys.mjs +++ b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/retry.sys.mjs @@ -27,7 +27,7 @@ class RetryModule extends Module { // processes. const uri = this.messageHandler.window.document.baseURI; if (!uri.includes("example.net")) { - await new Promise(r => {}); + await new Promise(() => {}); } return { ...params }; @@ -37,7 +37,7 @@ class RetryModule extends Module { async blockedOneTime(params) { callsToBlockedOneTime++; if (callsToBlockedOneTime < 2) { - await new Promise(r => {}); + await new Promise(() => {}); } // Return: @@ -51,7 +51,7 @@ class RetryModule extends Module { async blockedTenTimes(params) { callsToBlockedTenTimes++; if (callsToBlockedTenTimes < 11) { - await new Promise(r => {}); + await new Promise(() => {}); } // Return: @@ -65,7 +65,7 @@ class RetryModule extends Module { async blockedElevenTimes(params) { callsToBlockedElevenTimes++; if (callsToBlockedElevenTimes < 12) { - await new Promise(r => {}); + await new Promise(() => {}); } // Return: diff --git a/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/windowglobaltoroot.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/windowglobaltoroot.sys.mjs index 815a836d9c..1d9238f1bc 100644 --- a/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/windowglobaltoroot.sys.mjs +++ b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/windowglobaltoroot.sys.mjs @@ -17,7 +17,7 @@ class WindowGlobalToRootModule extends Module { * Commands */ - testHandleCommandToRoot(params, destination) { + testHandleCommandToRoot() { return this.messageHandler.handleCommand({ moduleName: "windowglobaltoroot", commandName: "getValueFromRoot", @@ -27,7 +27,7 @@ class WindowGlobalToRootModule extends Module { }); } - testSendRootCommand(params, destination) { + testSendRootCommand() { return this.messageHandler.sendRootCommand({ moduleName: "windowglobaltoroot", commandName: "getValueFromRoot", diff --git a/remote/shared/test/browser/browser_UserContextManager.js b/remote/shared/test/browser/browser_UserContextManager.js index 2060c2bacd..cfae75dbe2 100644 --- a/remote/shared/test/browser/browser_UserContextManager.js +++ b/remote/shared/test/browser/browser_UserContextManager.js @@ -159,8 +159,9 @@ add_task(async function test_several_managers() { "manager2 has a valid id for the user context created by manager 1" ); - ok( - contextId1 != contextId2, + Assert.notEqual( + contextId1, + contextId2, "manager1 and manager2 have different ids for the same internal context id" ); diff --git a/remote/shared/test/xpcshell/test_RecommendedPreferences.js b/remote/shared/test/xpcshell/test_RecommendedPreferences.js index 20de07a528..88dc717be8 100644 --- a/remote/shared/test/xpcshell/test_RecommendedPreferences.js +++ b/remote/shared/test/xpcshell/test_RecommendedPreferences.js @@ -76,6 +76,11 @@ add_task(async function test_disabled() { add_task(async function test_noCustomPreferences() { info("Applying preferences without any custom preference should not throw"); + + // First call invokes setting of default preferences + RecommendedPreferences.applyPreferences(); + + // Second call does nothing RecommendedPreferences.applyPreferences(); cleanup(); diff --git a/remote/shared/test/xpcshell/test_Sync.js b/remote/shared/test/xpcshell/test_Sync.js index de4a4d30fe..a85c47adc2 100644 --- a/remote/shared/test/xpcshell/test_Sync.js +++ b/remote/shared/test/xpcshell/test_Sync.js @@ -50,14 +50,14 @@ class MockElement { } } - dispatchEvent(event) { + dispatchEvent() { if (this.wantUntrusted) { this.untrusted = true; } this.click(); } - removeEventListener(name, func) { + removeEventListener() { this.capture = false; this.eventName = null; this.func = null; @@ -213,12 +213,12 @@ add_task(async function test_EventPromise_checkFnCallback() { { checkFn: null, expected_count: 0 }, { checkFn: undefined, expected_count: 0 }, { - checkFn: event => { + checkFn: () => { throw new Error("foo"); }, expected_count: 0, }, - { checkFn: event => count++ > 0, expected_count: 2 }, + { checkFn: () => count++ > 0, expected_count: 2 }, ]; for (const { checkFn, expected_count } of data) { @@ -417,7 +417,7 @@ add_task(async function test_PollPromise_resolve() { const timeout = 100; await new PollPromise( - (resolve, reject) => { + resolve => { resolve(); }, { timeout, errorMessage } diff --git a/remote/shared/webdriver/Actions.sys.mjs b/remote/shared/webdriver/Actions.sys.mjs index 4f5a41a421..2639c4dc9f 100644 --- a/remote/shared/webdriver/Actions.sys.mjs +++ b/remote/shared/webdriver/Actions.sys.mjs @@ -13,7 +13,7 @@ ChromeUtils.defineESModuleGetters(lazy, { clearTimeout: "resource://gre/modules/Timer.sys.mjs", dom: "chrome://remote/content/shared/DOM.sys.mjs", error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs", - event: "chrome://remote/content/marionette/event.sys.mjs", + event: "chrome://remote/content/shared/webdriver/Event.sys.mjs", keyData: "chrome://remote/content/shared/webdriver/KeyData.sys.mjs", Log: "chrome://remote/content/shared/Log.sys.mjs", pprint: "chrome://remote/content/shared/Format.sys.mjs", @@ -508,11 +508,8 @@ class Origin { * Viewport coordinates of the origin of this coordinate system. * * This is overridden in subclasses to provide a class-specific origin. - * - * @param {InputSource} inputSource - State of current input device. - * @param {WindowProxy} win - Current window global */ - getOriginCoordinates(inputSource, win) { + getOriginCoordinates() { throw new Error( `originCoordinates not defined for ${this.constructor.name}` ); @@ -559,13 +556,13 @@ class Origin { } class ViewportOrigin extends Origin { - getOriginCoordinates(inputSource, win) { + getOriginCoordinates() { return { x: 0, y: 0 }; } } class PointerOrigin extends Origin { - getOriginCoordinates(inputSource, win) { + getOriginCoordinates(inputSource) { return { x: inputSource.x, y: inputSource.y }; } } @@ -624,13 +621,9 @@ class Action { * This is overridden by subclasses to implement the type-specific * dispatch of the action. * - * @param {State} state - Actions state. - * @param {InputSource} inputSource - State of the current input device. - * @param {number} tickDuration - Length of the current tick, in ms. - * @param {WindowProxy} win - Current window global. * @returns {Promise} - Promise that is resolved once the action is complete. */ - dispatch(state, inputSource, tickDuration, win) { + dispatch() { throw new Error( `Action subclass ${this.constructor.name} must override dispatch()` ); @@ -708,10 +701,9 @@ class PauseAction extends NullAction { * @param {State} state - Actions state. * @param {InputSource} inputSource - State of the current input device. * @param {number} tickDuration - Length of the current tick, in ms. - * @param {WindowProxy} win - Current window global. * @returns {Promise} - Promise that is resolved once the action is complete. */ - dispatch(state, inputSource, tickDuration, win) { + dispatch(state, inputSource, tickDuration) { const ms = this.duration ?? tickDuration; lazy.logger.trace( @@ -1416,15 +1408,9 @@ class TouchActionGroup { * This is overridden by subclasses to implement the type-specific * dispatch of the action. * - * @param {State} state - Actions state. - * @param {null} inputSource - * This is always null; the argument only exists for compatibility - * with {@link Action.dispatch}. - * @param {number} tickDuration - Length of the current tick, in ms. - * @param {WindowProxy} win - Current window global. * @returns {Promise} - Promise that is resolved once the action is complete. */ - dispatch(state, inputSource, tickDuration, win) { + dispatch() { throw new Error( "TouchActionGroup subclass missing dispatch implementation" ); @@ -1622,7 +1608,7 @@ class PointerMoveTouchActionGroup extends TouchActionGroup { } ); const reachedTarget = perPointerData.every( - ([inputSource, action, target]) => + ([inputSource, , target]) => target[0] === inputSource.x && target[1] === inputSource.y ); @@ -1778,38 +1764,22 @@ class Pointer { /** * Implementation of depressing the pointer. - * - * @param {State} state - Actions state. - * @param {InputSource} inputSource - State of the current input device. - * @param {Action} action - The Action object invoking the pointer - * @param {WindowProxy} win - Current window global. */ - pointerDown(state, inputSource, action, win) { + pointerDown() { throw new Error(`Unimplemented pointerDown for pointerType ${this.type}`); } /** * Implementation of releasing the pointer. - * - * @param {State} state - Actions state. - * @param {InputSource} inputSource - State of the current input device. - * @param {Action} action - The Action object invoking the pointer - * @param {WindowProxy} win - Current window global. */ - pointerUp(state, inputSource, action, win) { + pointerUp() { throw new Error(`Unimplemented pointerUp for pointerType ${this.type}`); } /** * Implementation of moving the pointer. - * - * @param {State} state - Actions state. - * @param {InputSource} inputSource - State of the current input device. - * @param {number} targetX - Target X coordinate of the pointer move - * @param {number} targetY - Target Y coordinate of the pointer move - * @param {WindowProxy} win - Current window global. */ - pointerMove(state, inputSource, targetX, targetY, win) { + pointerMove() { throw new Error(`Unimplemented pointerMove for pointerType ${this.type}`); } @@ -2138,11 +2108,8 @@ class InputEventData { /** * Update the input data based on global and input state - * - * @param {State} state - Actions state. - * @param {InputSource} inputSource - State of the current input device. */ - update(state, inputSource) {} + update() {} toString() { return `${this.constructor.name} ${JSON.stringify(this)}`; diff --git a/remote/shared/webdriver/Capabilities.sys.mjs b/remote/shared/webdriver/Capabilities.sys.mjs index e3761315f2..3c30ea0789 100644 --- a/remote/shared/webdriver/Capabilities.sys.mjs +++ b/remote/shared/webdriver/Capabilities.sys.mjs @@ -445,6 +445,12 @@ export class Capabilities extends Map { ["timeouts", new Timeouts()], ["strictFileInteractability", false], ["unhandledPromptBehavior", UnhandledPromptBehavior.DismissAndNotify], + [ + "userAgent", + Cc["@mozilla.org/network/protocol;1?name=http"].getService( + Ci.nsIHttpProtocolHandler + ).userAgent, + ], ["webSocketUrl", null], // proprietary diff --git a/remote/shared/webdriver/Errors.sys.mjs b/remote/shared/webdriver/Errors.sys.mjs index 53b9d4426b..7060131075 100644 --- a/remote/shared/webdriver/Errors.sys.mjs +++ b/remote/shared/webdriver/Errors.sys.mjs @@ -41,6 +41,7 @@ const ERRORS = new Set([ "TimeoutError", "UnableToCaptureScreen", "UnableToSetCookieError", + "UnableToSetFileInputError", "UnexpectedAlertOpenError", "UnknownCommandError", "UnknownError", @@ -757,6 +758,21 @@ class UnableToSetCookieError extends WebDriverError { } /** + * A command to set a file could not be satisfied. + * + * @param {string=} message + * Optional string describing error situation. + * @param {object=} data + * Additional error data helpful in diagnosing the error. + */ +class UnableToSetFileInputError extends WebDriverError { + constructor(message, data = {}) { + super(message, data); + this.status = "unable to set file input"; + } +} + +/** * A command to capture a screenshot could not be satisfied. * * @param {string=} message @@ -865,6 +881,7 @@ const STATUSES = new Map([ ["timeout", TimeoutError], ["unable to capture screen", UnableToCaptureScreen], ["unable to set cookie", UnableToSetCookieError], + ["unable to set file input", UnableToSetFileInputError], ["unexpected alert open", UnexpectedAlertOpenError], ["unknown command", UnknownCommandError], ["unknown error", UnknownError], diff --git a/remote/marionette/event.sys.mjs b/remote/shared/webdriver/Event.sys.mjs index dbe6567e52..2240f1f2b2 100644 --- a/remote/marionette/event.sys.mjs +++ b/remote/shared/webdriver/Event.sys.mjs @@ -278,6 +278,10 @@ event.mouseup = function (el, modifiers = {}, opts = {}) { return event.sendEvent("mouseup", el, modifiers, opts); }; +event.cancel = function (el, modifiers = {}, opts = {}) { + return event.sendEvent("cancel", el, modifiers, opts); +}; + event.click = function (el, modifiers = {}, opts = {}) { return event.sendEvent("click", el, modifiers, opts); }; diff --git a/remote/shared/webdriver/process-actors/WebDriverProcessDataChild.sys.mjs b/remote/shared/webdriver/process-actors/WebDriverProcessDataChild.sys.mjs index 39db9d939e..8101240abe 100644 --- a/remote/shared/webdriver/process-actors/WebDriverProcessDataChild.sys.mjs +++ b/remote/shared/webdriver/process-actors/WebDriverProcessDataChild.sys.mjs @@ -17,7 +17,7 @@ class BrowsingContextObserver { this.actor = actor; } - async observe(subject, topic, data) { + async observe(subject, topic) { if (topic === "browsing-context-discarded") { this.actor.cleanUp({ browsingContext: subject }); } diff --git a/remote/shared/webdriver/test/xpcshell/test_Errors.js b/remote/shared/webdriver/test/xpcshell/test_Errors.js index 22e3526039..d4803dee87 100644 --- a/remote/shared/webdriver/test/xpcshell/test_Errors.js +++ b/remote/shared/webdriver/test/xpcshell/test_Errors.js @@ -36,6 +36,7 @@ const errors = [ error.StaleElementReferenceError, error.TimeoutError, error.UnableToSetCookieError, + error.UnableToSetFileInputError, error.UnexpectedAlertOpenError, error.UnknownCommandError, error.UnknownError, @@ -510,6 +511,14 @@ add_task(function test_UnableToSetCookieError() { ok(err instanceof error.WebDriverError); }); +add_task(function test_UnableToSetFileInputError() { + let err = new error.UnableToSetFileInputError("foo"); + equal("UnableToSetFileInputError", err.name); + equal("foo", err.message); + equal("unable to set file input", err.status); + ok(err instanceof error.WebDriverError); +}); + add_task(function test_UnexpectedAlertOpenError() { let err = new error.UnexpectedAlertOpenError("foo"); equal("UnexpectedAlertOpenError", err.name); diff --git a/remote/test/puppeteer/.eslintrc.js b/remote/test/puppeteer/.eslintrc.js index 250aa0c169..6bd3e4538d 100644 --- a/remote/test/puppeteer/.eslintrc.js +++ b/remote/test/puppeteer/.eslintrc.js @@ -150,7 +150,7 @@ module.exports = { // Enforces consistent file extension 'rulesdir/extensions': 'error', // Enforces license headers on files - 'rulesdir/check-license': 'warn', + 'rulesdir/check-license': 'error', }, overrides: [ { @@ -172,8 +172,6 @@ module.exports = { curly: ['error', 'all'], // Brackets keep code readable and `return` intentions clear. 'arrow-body-style': ['error', 'always'], - // Error if comments do not adhere to `tsdoc`. - 'tsdoc/syntax': 'error', // Keeps array types simple only when they are simple for readability. '@typescript-eslint/array-type': ['error', {default: 'array-simple'}], 'no-unused-vars': 'off', @@ -277,5 +275,14 @@ module.exports = { }, ], }, + + { + // Applies to only published packages + files: ['packages/**/*.ts'], + rules: { + // Error if comments do not adhere to `tsdoc`. + 'tsdoc/syntax': 'error', + }, + }, ], }; diff --git a/remote/test/puppeteer/.npmrc b/remote/test/puppeteer/.npmrc index 94a06c2180..1f6bc691f6 100644 --- a/remote/test/puppeteer/.npmrc +++ b/remote/test/puppeteer/.npmrc @@ -1 +1,2 @@ access=public +install-strategy=nested diff --git a/remote/test/puppeteer/.release-please-manifest.json b/remote/test/puppeteer/.release-please-manifest.json index 1237fb11dd..a3ccb1a4ae 100644 --- a/remote/test/puppeteer/.release-please-manifest.json +++ b/remote/test/puppeteer/.release-please-manifest.json @@ -1,7 +1,7 @@ { - "packages/puppeteer": "21.10.0", - "packages/puppeteer-core": "21.10.0", + "packages/puppeteer": "22.4.0", + "packages/puppeteer-core": "22.4.0", "packages/testserver": "0.6.0", - "packages/ng-schematics": "0.5.6", - "packages/browsers": "1.9.1" + "packages/ng-schematics": "0.6.0", + "packages/browsers": "2.1.0" } diff --git a/remote/test/puppeteer/README.md b/remote/test/puppeteer/README.md index 74a15c6eb9..288a5b623c 100644 --- a/remote/test/puppeteer/README.md +++ b/remote/test/puppeteer/README.md @@ -181,7 +181,7 @@ import puppeteer from 'puppeteer'; **1. Uses Headless mode** By default Puppeteer launches Chrome in -[old Headless mode](https://developer.chrome.com/articles/new-headless/). +[the Headless mode](https://developer.chrome.com/articles/new-headless/). ```ts const browser = await puppeteer.launch(); @@ -189,12 +189,16 @@ const browser = await puppeteer.launch(); const browser = await puppeteer.launch({headless: true}); ``` -[Chrome 112 launched a new Headless mode](https://developer.chrome.com/articles/new-headless/) that might cause some differences in behavior compared to the old Headless implementation. -In the future Puppeteer will start defaulting to new implementation. -We recommend you try it out before the switch: +Before v22, Puppeteer launched the [old Headless mode](https://developer.chrome.com/articles/new-headless/) by default. +The old headless mode is now known as +[`chrome-headless-shell`](https://developer.chrome.com/blog/chrome-headless-shell) +and ships as a separate binary. `chrome-headless-shell` does not match the +behavior of the regular Chrome completely but it is currently more performant +for automation tasks where the complete Chrome feature set is not needed. If the performance +is more important for your use case, switch to `chrome-headless-shell` as following: ```ts -const browser = await puppeteer.launch({headless: 'new'}); +const browser = await puppeteer.launch({headless: 'shell'}); ``` To launch a "headful" version of Chrome, set the diff --git a/remote/test/puppeteer/examples/README.md b/remote/test/puppeteer/examples/README.md index f20c2e7162..92e83eb39c 100644 --- a/remote/test/puppeteer/examples/README.md +++ b/remote/test/puppeteer/examples/README.md @@ -36,8 +36,4 @@ Other useful tools, articles, and projects that use Puppeteer. - [puppeteer-loadtest](https://github.com/svenkatreddy/puppeteer-loadtest) - commandline interface for performing load test on puppeteer scripts. - [cucumber-puppeteer-example](https://github.com/mlampedx/cucumber-puppeteer-example) - Example repository demonstrating how to use Puppeeteer and Cucumber for integration testing. -## Services - -- [Checkly](https://checklyhq.com) - Monitoring SaaS that uses Puppeteer to check availability and correctness of web pages and apps. -- [Doppio](https://doppio.sh) - SaaS API to create screenshots or PDFs from HTML/CSS/JS -- [Doczilla](https://www.doczilla.app) - SaaS API empowering the generation of screenshots or PDFs directly from HTML/CSS/JS code. +Also, see the [community list of Puppeteer resources](https://github.com/transitive-bullshit/awesome-puppeteer) for more examples. diff --git a/remote/test/puppeteer/examples/cross-browser.js b/remote/test/puppeteer/examples/cross-browser.js index 0f972a0b70..037dba2482 100644 --- a/remote/test/puppeteer/examples/cross-browser.js +++ b/remote/test/puppeteer/examples/cross-browser.js @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ const puppeteer = require('puppeteer'); /** diff --git a/remote/test/puppeteer/moz.yaml b/remote/test/puppeteer/moz.yaml index 5f732140c9..35363b67dc 100644 --- a/remote/test/puppeteer/moz.yaml +++ b/remote/test/puppeteer/moz.yaml @@ -5,6 +5,6 @@ origin: description: Headless Chrome Node API license: Apache-2.0 name: puppeteer - release: puppeteer-v21.10.0 + release: puppeteer-v22.4.0 url: ../puppeteer schema: 1 diff --git a/remote/test/puppeteer/package-lock.json b/remote/test/puppeteer/package-lock.json index 76878ce829..b1fb3b0189 100644 --- a/remote/test/puppeteer/package-lock.json +++ b/remote/test/puppeteer/package-lock.json @@ -19,34 +19,34 @@ "@actions/core": "1.10.1", "@types/mocha": "10.0.6", "@types/node": "20.8.4", - "@types/semver": "7.5.6", + "@types/semver": "7.5.8", "@types/sinon": "17.0.3", - "@typescript-eslint/eslint-plugin": "6.19.1", - "@typescript-eslint/parser": "6.19.1", - "esbuild": "0.20.0", - "eslint": "8.56.0", + "@typescript-eslint/eslint-plugin": "7.1.0", + "@typescript-eslint/parser": "7.1.0", + "esbuild": "0.20.1", + "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-import-resolver-typescript": "3.6.1", "eslint-plugin-import": "2.29.1", - "eslint-plugin-mocha": "10.2.0", + "eslint-plugin-mocha": "10.3.0", "eslint-plugin-prettier": "5.1.3", "eslint-plugin-rulesdir": "0.2.2", "eslint-plugin-tsdoc": "0.2.17", - "eslint-plugin-unused-imports": "3.0.0", + "eslint-plugin-unused-imports": "3.1.0", "execa": "8.0.1", "expect": "29.7.0", "gts": "5.2.0", "hereby": "1.8.9", "license-checker": "25.0.1", - "mocha": "10.2.0", - "npm-run-all": "4.1.5", - "prettier": "3.2.4", - "semver": "7.5.4", + "mocha": "10.3.0", + "npm-run-all2": "6.1.2", + "prettier": "3.2.5", + "semver": "7.6.0", "sinon": "17.0.1", "source-map-support": "0.5.21", "spdx-satisfies": "5.0.1", - "tsd": "0.30.4", - "tsx": "4.7.0", + "tsd": "0.30.7", + "tsx": "4.7.1", "typescript": "5.3.3", "wireit": "0.14.4" } @@ -247,374 +247,6 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.0.tgz", - "integrity": "sha512-fGFDEctNh0CcSwsiRPxiaqX0P5rq+AqE0SRhYGZ4PX46Lg1FNR6oCxJghf8YgY0WQEgQuh3lErUFE4KxLeRmmw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.0.tgz", - "integrity": "sha512-3bMAfInvByLHfJwYPJRlpTeaQA75n8C/QKpEaiS4HrFWFiJlNI0vzq/zCjBrhAYcPyVPG7Eo9dMrcQXuqmNk5g==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.0.tgz", - "integrity": "sha512-aVpnM4lURNkp0D3qPoAzSG92VXStYmoVPOgXveAUoQBWRSuQzt51yvSju29J6AHPmwY1BjH49uR29oyfH1ra8Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.0.tgz", - "integrity": "sha512-uK7wAnlRvjkCPzh8jJ+QejFyrP8ObKuR5cBIsQZ+qbMunwR8sbd8krmMbxTLSrDhiPZaJYKQAU5Y3iMDcZPhyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.0.tgz", - "integrity": "sha512-AjEcivGAlPs3UAcJedMa9qYg9eSfU6FnGHJjT8s346HSKkrcWlYezGE8VaO2xKfvvlZkgAhyvl06OJOxiMgOYQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.0.tgz", - "integrity": "sha512-bsgTPoyYDnPv8ER0HqnJggXK6RyFy4PH4rtsId0V7Efa90u2+EifxytE9pZnsDgExgkARy24WUQGv9irVbTvIw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.0.tgz", - "integrity": "sha512-kQ7jYdlKS335mpGbMW5tEe3IrQFIok9r84EM3PXB8qBFJPSc6dpWfrtsC/y1pyrz82xfUIn5ZrnSHQQsd6jebQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.0.tgz", - "integrity": "sha512-uG8B0WSepMRsBNVXAQcHf9+Ko/Tr+XqmK7Ptel9HVmnykupXdS4J7ovSQUIi0tQGIndhbqWLaIL/qO/cWhXKyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.0.tgz", - "integrity": "sha512-2ezuhdiZw8vuHf1HKSf4TIk80naTbP9At7sOqZmdVwvvMyuoDiZB49YZKLsLOfKIr77+I40dWpHVeY5JHpIEIg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.0.tgz", - "integrity": "sha512-uTtyYAP5veqi2z9b6Gr0NUoNv9F/rOzI8tOD5jKcCvRUn7T60Bb+42NDBCWNhMjkQzI0qqwXkQGo1SY41G52nw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.0.tgz", - "integrity": "sha512-c88wwtfs8tTffPaoJ+SQn3y+lKtgTzyjkD8NgsyCtCmtoIC8RDL7PrJU05an/e9VuAke6eJqGkoMhJK1RY6z4w==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.0.tgz", - "integrity": "sha512-lR2rr/128/6svngnVta6JN4gxSXle/yZEZL3o4XZ6esOqhyR4wsKyfu6qXAL04S4S5CgGfG+GYZnjFd4YiG3Aw==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.0.tgz", - "integrity": "sha512-9Sycc+1uUsDnJCelDf6ZNqgZQoK1mJvFtqf2MUz4ujTxGhvCWw+4chYfDLPepMEvVL9PDwn6HrXad5yOrNzIsQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.0.tgz", - "integrity": "sha512-CoWSaaAXOZd+CjbUTdXIJE/t7Oz+4g90A3VBCHLbfuc5yUQU/nFDLOzQsN0cdxgXd97lYW/psIIBdjzQIwTBGw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.0.tgz", - "integrity": "sha512-mlb1hg/eYRJUpv8h/x+4ShgoNLL8wgZ64SUr26KwglTYnwAWjkhR2GpoKftDbPOCnodA9t4Y/b68H4J9XmmPzA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.0.tgz", - "integrity": "sha512-fgf9ubb53xSnOBqyvWEY6ukBNRl1mVX1srPNu06B6mNsNK20JfH6xV6jECzrQ69/VMiTLvHMicQR/PgTOgqJUQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.0.tgz", - "integrity": "sha512-H9Eu6MGse++204XZcYsse1yFHmRXEWgadk2N58O/xd50P9EvFMLJTQLg+lB4E1cF2xhLZU5luSWtGTb0l9UeSg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.0.tgz", - "integrity": "sha512-lCT675rTN1v8Fo+RGrE5KjSnfY0x9Og4RN7t7lVrN3vMSjy34/+3na0q7RIfWDAj0e0rCh0OL+P88lu3Rt21MQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.0.tgz", - "integrity": "sha512-HKoUGXz/TOVXKQ+67NhxyHv+aDSZf44QpWLa3I1lLvAwGq8x1k0T+e2HHSRvxWhfJrFxaaqre1+YyzQ99KixoA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.0.tgz", - "integrity": "sha512-GDwAqgHQm1mVoPppGsoq4WJwT3vhnz/2N62CzhvApFD1eJyTroob30FPpOZabN+FgCjhG+AgcZyOPIkR8dfD7g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.0.tgz", - "integrity": "sha512-0vYsP8aC4TvMlOQYozoksiaxjlvUcQrac+muDqj1Fxy6jh9l9CZJzj7zmh8JGfiV49cYLTorFLxg7593pGldwQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.0.tgz", - "integrity": "sha512-p98u4rIgfh4gdpV00IqknBD5pC84LCub+4a3MO+zjqvU5MVXOc3hqR2UgT2jI2nh3h8s9EQxmOsVI3tyzv1iFg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.0.tgz", - "integrity": "sha512-NgJnesu1RtWihtTtXGFMU5YSE6JyyHPMxCwBZK7a6/8d31GuSo9l0Ss7w1Jw5QnKUawG6UEehs883kcXf5fYwg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -684,15 +316,6 @@ "node": "*" } }, - "node_modules/@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "node_modules/@fastify/busboy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", @@ -897,9 +520,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "engines": { "node": ">=6.0.0" @@ -920,29 +543,17 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@ljharb/through": { - "version": "2.3.12", - "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.12.tgz", - "integrity": "sha512-ajo/heTlG3QgC8EGP6APIejksVAYt4ayz4tqoP3MolFELzcH1x1fzwEYRJTPO0IELutZ5HQ0c26/GqAYy79u3g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/@microsoft/api-documenter": { - "version": "7.23.20", - "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.23.20.tgz", - "integrity": "sha512-61V6sukyYZ5jQEdyvDFzInaIRTd0wgT2ECKPanr2ba0fc+Mien+KIr5shz9EAqJMZz0GifTnw9HmJqsfR688xA==", + "version": "7.23.35", + "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.23.35.tgz", + "integrity": "sha512-zSHTX0abumOsfA3GsWJADFtiqxgwcoSCGSO+84e4s/SWotAqlUwXMYVJk6/huJFKSL+LG46gvcn7r8bsOd3K2Q==", "dev": true, "dependencies": { - "@microsoft/api-extractor-model": "7.28.7", + "@microsoft/api-extractor-model": "7.28.13", "@microsoft/tsdoc": "0.14.2", - "@rushstack/node-core-library": "3.64.2", - "@rushstack/ts-command-line": "4.17.1", - "colors": "~1.2.1", + "@rushstack/node-core-library": "4.0.2", + "@rushstack/terminal": "0.10.0", + "@rushstack/ts-command-line": "4.19.0", "js-yaml": "~3.13.1", "resolve": "~1.22.1" }, @@ -950,6 +561,60 @@ "api-documenter": "bin/api-documenter" } }, + "node_modules/@microsoft/api-documenter/node_modules/@rushstack/terminal": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.10.0.tgz", + "integrity": "sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==", + "dev": true, + "dependencies": { + "@rushstack/node-core-library": "4.0.2", + "supports-color": "~8.1.1" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@microsoft/api-documenter/node_modules/@rushstack/terminal/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@microsoft/api-documenter/node_modules/@rushstack/ts-command-line": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.19.0.tgz", + "integrity": "sha512-0sIHWOFGLFb6tC1zk2R0aM79ic3CF0XGzVBvhf6ytMyjDwt03DVb1qe5/5NQ0FGcvB5YyQ2WVfGsnxG6SANvHA==", + "dev": true, + "dependencies": { + "@rushstack/terminal": "0.10.0", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" + } + }, + "node_modules/@microsoft/api-documenter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, "node_modules/@microsoft/api-documenter/node_modules/js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -963,20 +628,27 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/@microsoft/api-documenter/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, "node_modules/@microsoft/api-extractor": { - "version": "7.39.4", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.39.4.tgz", - "integrity": "sha512-6YvfkpbEqRQ0UPdVBc+lOiq7VlXi9kw8U3w+RcXCFDVc/UljlXU5l9fHEyuBAW1GGO2opUe+yf9OscWhoHANhg==", + "version": "7.42.2", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.42.2.tgz", + "integrity": "sha512-HYiOQDO4WR+Pj4XQZZE5qK5R6e3MF6Ut5s+Hi2IkeI6MiCXkdmRugQH6ppc9YzTUiydRqZ+jshZD7UWNGSA8bg==", "dev": true, "dependencies": { - "@microsoft/api-extractor-model": "7.28.7", + "@microsoft/api-extractor-model": "7.28.13", "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.64.2", - "@rushstack/rig-package": "0.5.1", - "@rushstack/ts-command-line": "4.17.1", - "colors": "~1.2.1", + "@rushstack/node-core-library": "4.0.2", + "@rushstack/rig-package": "0.5.2", + "@rushstack/terminal": "0.10.0", + "@rushstack/ts-command-line": "4.19.0", "lodash": "~4.17.15", + "minimatch": "~3.0.3", "resolve": "~1.22.1", "semver": "~7.5.4", "source-map": "~0.6.1", @@ -987,14 +659,111 @@ } }, "node_modules/@microsoft/api-extractor-model": { - "version": "7.28.7", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.7.tgz", - "integrity": "sha512-4gCGGEQGHmbQmarnDcEWS2cjj0LtNuD3D6rh3ZcAyAYTkceAugAk2eyQHGdTcGX8w3qMjWCTU1TPb8xHnMM+Kg==", + "version": "7.28.13", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.13.tgz", + "integrity": "sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==", "dev": true, "dependencies": { "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.64.2" + "@rushstack/node-core-library": "4.0.2" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/terminal": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.10.0.tgz", + "integrity": "sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==", + "dev": true, + "dependencies": { + "@rushstack/node-core-library": "4.0.2", + "supports-color": "~8.1.1" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/terminal/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/ts-command-line": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.19.0.tgz", + "integrity": "sha512-0sIHWOFGLFb6tC1zk2R0aM79ic3CF0XGzVBvhf6ytMyjDwt03DVb1qe5/5NQ0FGcvB5YyQ2WVfGsnxG6SANvHA==", + "dev": true, + "dependencies": { + "@rushstack/terminal": "0.10.0", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/ts-command-line/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/ts-command-line/node_modules/argparse/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/@microsoft/api-extractor/node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/minimatch/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/@microsoft/tsdoc": { @@ -1063,268 +832,6 @@ "node": ">= 8" } }, - "node_modules/@npmcli/agent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.0.tgz", - "integrity": "sha512-2yThA1Es98orMkpSLVqlDZAMPK3jHJhifP2gnNUdk1754uZ8yI5c+ulCoVG+WlntQA6MzhrURMXjSd9Z7dJ2/Q==", - "dev": true, - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/agent/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/@npmcli/fs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", - "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", - "dev": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/git": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.4.tgz", - "integrity": "sha512-nr6/WezNzuYUppzXRaYu/W4aT5rLxdXqEFupbh6e/ovlYFQ8hpu1UUPV3Ir/YTl+74iXl2ZOMlGzudh9ZPUchQ==", - "dev": true, - "dependencies": { - "@npmcli/promise-spawn": "^7.0.0", - "lru-cache": "^10.0.1", - "npm-pick-manifest": "^9.0.0", - "proc-log": "^3.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^4.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/git/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/@npmcli/git/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "dev": true, - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/installed-package-contents": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", - "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", - "dev": true, - "dependencies": { - "npm-bundled": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "bin": { - "installed-package-contents": "lib/index.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/installed-package-contents/node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/node-gyp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", - "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/package-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.0.0.tgz", - "integrity": "sha512-OI2zdYBLhQ7kpNPaJxiflofYIpkNLi+lnGdzqUOfRmCF3r2l1nadcjtCYMJKv/Utm/ZtlffaUuTiAktPHbc17g==", - "dev": true, - "dependencies": { - "@npmcli/git": "^5.0.0", - "glob": "^10.2.2", - "hosted-git-info": "^7.0.0", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^6.0.0", - "proc-log": "^3.0.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/package-json/node_modules/hosted-git-info": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", - "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", - "dev": true, - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/package-json/node_modules/json-parse-even-better-errors": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", - "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/package-json/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/@npmcli/package-json/node_modules/normalize-package-data": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", - "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", - "dev": true, - "dependencies": { - "hosted-git-info": "^7.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/promise-spawn": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.1.tgz", - "integrity": "sha512-P4KkF9jX3y+7yFUxgcUdDtLy+t4OlDGuEBLNs57AZsfSfg+uV6MLndqGpnl4831ggaEdXwR50XFoZP4VFtHolg==", - "dev": true, - "dependencies": { - "which": "^4.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/promise-spawn/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/@npmcli/promise-spawn/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "dev": true, - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/run-script": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", - "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", - "dev": true, - "dependencies": { - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/package-json": "^5.0.0", - "@npmcli/promise-spawn": "^7.0.0", - "node-gyp": "^10.0.0", - "which": "^4.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/run-script/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/@npmcli/run-script/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "dev": true, - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -1351,12 +858,12 @@ "link": true }, "node_modules/@prettier/sync": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@prettier/sync/-/sync-0.5.0.tgz", - "integrity": "sha512-1a6veNypZYkSbU33anha4Pdna9Jz3HXUc0aru7sgN7HuyJHPIVNdCTfjhm1S+mG9yXmWuAO+a6I+Cznp9Ogt3A==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@prettier/sync/-/sync-0.5.1.tgz", + "integrity": "sha512-tpF+A1e4ynO2U4fTH21Sjgm9EYENmqg4zmJCMLrmLVfzIzuDc1cKGXyxrxbFgcH8qQRfowyDCZFAUukwhiZlsw==", "dev": true, "dependencies": { - "make-synchronized": "^0.2.5" + "make-synchronized": "^0.2.8" }, "funding": { "url": "https://github.com/prettier/prettier-synchronized?sponsor=1" @@ -1398,12 +905,11 @@ "link": true }, "node_modules/@rushstack/node-core-library": { - "version": "3.64.2", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.64.2.tgz", - "integrity": "sha512-n1S2VYEklONiwKpUyBq/Fym6yAsfsCXrqFabuOMcCuj4C+zW+HyaspSHXJCKqkMxfjviwe/c9+DUqvRWIvSN9Q==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz", + "integrity": "sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==", "dev": true, "dependencies": { - "colors": "~1.2.1", "fs-extra": "~7.0.1", "import-lazy": "~4.0.0", "jju": "~1.4.0", @@ -1420,98 +926,29 @@ } } }, - "node_modules/@rushstack/rig-package": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.1.tgz", - "integrity": "sha512-pXRYSe29TjRw7rqxD4WS3HN/sRSbfr+tJs4a9uuaSIBAITbUggygdhuG0VrO0EO+QqH91GhYMN4S6KRtOEmGVA==", - "dev": true, - "dependencies": { - "resolve": "~1.22.1", - "strip-json-comments": "~3.1.1" - } - }, - "node_modules/@rushstack/ts-command-line": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.17.1.tgz", - "integrity": "sha512-2jweO1O57BYP5qdBGl6apJLB+aRIn5ccIRTPDyULh0KMwVzFqWtw6IZWt1qtUoZD/pD2RNkIOosH6Cq45rIYeg==", - "dev": true, - "dependencies": { - "@types/argparse": "1.0.38", - "argparse": "~1.0.9", - "colors": "~1.2.1", - "string-argv": "~0.3.1" - } - }, - "node_modules/@sigstore/bundle": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.1.tgz", - "integrity": "sha512-v3/iS+1nufZdKQ5iAlQKcCsoh0jffQyABvYIxKsZQFWc4ubuGjwZklFHpDgV6O6T7vvV78SW5NHI91HFKEcxKg==", - "dev": true, - "dependencies": { - "@sigstore/protobuf-specs": "^0.2.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/core": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-0.2.0.tgz", - "integrity": "sha512-THobAPPZR9pDH2CAvDLpkrYedt7BlZnsyxDe+Isq4ZmGfPy5juOFZq487vCU2EgKD7aHSiTfE/i7sN7aEdzQnA==", - "dev": true, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/protobuf-specs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", - "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/sign": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.1.tgz", - "integrity": "sha512-U5sKQEj+faE1MsnLou1f4DQQHeFZay+V9s9768lw48J4pKykPj34rWyI1lsMOGJ3Mae47Ye6q3HAJvgXO21rkQ==", + "node_modules/@rushstack/node-core-library/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { - "@sigstore/bundle": "^2.1.1", - "@sigstore/core": "^0.2.0", - "@sigstore/protobuf-specs": "^0.2.1", - "make-fetch-happen": "^13.0.0" + "lru-cache": "^6.0.0" }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/tuf": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.0.tgz", - "integrity": "sha512-S98jo9cpJwO1mtQ+2zY7bOdcYyfVYCUaofCG6wWRzk3pxKHVAkSfshkfecto2+LKsx7Ovtqbgb2LS8zTRhxJ9Q==", - "dev": true, - "dependencies": { - "@sigstore/protobuf-specs": "^0.2.1", - "tuf-js": "^2.2.0" + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=10" } }, - "node_modules/@sigstore/verify": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-0.1.0.tgz", - "integrity": "sha512-2UzMNYAa/uaz11NhvgRnIQf4gpLTJ59bhb8ESXaoSS5sxedfS+eLak8bsdMc+qpNQfITUTFoSKFx5h8umlRRiA==", + "node_modules/@rushstack/rig-package": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.2.tgz", + "integrity": "sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==", "dev": true, "dependencies": { - "@sigstore/bundle": "^2.1.1", - "@sigstore/core": "^0.2.0", - "@sigstore/protobuf-specs": "^0.2.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" + "resolve": "~1.22.1", + "strip-json-comments": "~3.1.1" } }, "node_modules/@sinclair/typebox": { @@ -1565,13 +1002,13 @@ "dev": true }, "node_modules/@swc/core": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.107.tgz", - "integrity": "sha512-zKhqDyFcTsyLIYK1iEmavljZnf4CCor5pF52UzLAz4B6Nu/4GLU+2LQVAf+oRHjusG39PTPjd2AlRT3f3QWfsQ==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.4.2.tgz", + "integrity": "sha512-vWgY07R/eqj1/a0vsRKLI9o9klGZfpLNOVEnrv4nrccxBgYPjcf22IWwAoaBJ+wpA7Q4fVjCUM8lP0m01dpxcg==", "dev": true, "hasInstallScript": true, "dependencies": { - "@swc/counter": "^0.1.1", + "@swc/counter": "^0.1.2", "@swc/types": "^0.1.5" }, "engines": { @@ -1582,16 +1019,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.107", - "@swc/core-darwin-x64": "1.3.107", - "@swc/core-linux-arm-gnueabihf": "1.3.107", - "@swc/core-linux-arm64-gnu": "1.3.107", - "@swc/core-linux-arm64-musl": "1.3.107", - "@swc/core-linux-x64-gnu": "1.3.107", - "@swc/core-linux-x64-musl": "1.3.107", - "@swc/core-win32-arm64-msvc": "1.3.107", - "@swc/core-win32-ia32-msvc": "1.3.107", - "@swc/core-win32-x64-msvc": "1.3.107" + "@swc/core-darwin-arm64": "1.4.2", + "@swc/core-darwin-x64": "1.4.2", + "@swc/core-linux-arm-gnueabihf": "1.4.2", + "@swc/core-linux-arm64-gnu": "1.4.2", + "@swc/core-linux-arm64-musl": "1.4.2", + "@swc/core-linux-x64-gnu": "1.4.2", + "@swc/core-linux-x64-musl": "1.4.2", + "@swc/core-win32-arm64-msvc": "1.4.2", + "@swc/core-win32-ia32-msvc": "1.4.2", + "@swc/core-win32-x64-msvc": "1.4.2" }, "peerDependencies": { "@swc/helpers": "^0.5.0" @@ -1602,10 +1039,10 @@ } } }, - "node_modules/@swc/core-darwin-arm64": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.107.tgz", - "integrity": "sha512-47tD/5vSXWxPd0j/ZllyQUg4bqalbQTsmqSw0J4dDdS82MWqCAwUErUrAZPRjBkjNQ6Kmrf5rpCWaGTtPw+ngw==", + "node_modules/@swc/core/node_modules/@swc/core-darwin-arm64": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.2.tgz", + "integrity": "sha512-1uSdAn1MRK5C1m/TvLZ2RDvr0zLvochgrZ2xL+lRzugLlCTlSA+Q4TWtrZaOz+vnnFVliCpw7c7qu0JouhgQIw==", "cpu": [ "arm64" ], @@ -1618,10 +1055,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.107.tgz", - "integrity": "sha512-hwiLJ2ulNkBGAh1m1eTfeY1417OAYbRGcb/iGsJ+LuVLvKAhU/itzsl535CvcwAlt2LayeCFfcI8gdeOLeZa9A==", + "node_modules/@swc/core/node_modules/@swc/core-darwin-x64": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.4.2.tgz", + "integrity": "sha512-TYD28+dCQKeuxxcy7gLJUCFLqrwDZnHtC2z7cdeGfZpbI2mbfppfTf2wUPzqZk3gEC96zHd4Yr37V3Tvzar+lQ==", "cpu": [ "x64" ], @@ -1634,10 +1071,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.107.tgz", - "integrity": "sha512-I2wzcC0KXqh0OwymCmYwNRgZ9nxX7DWnOOStJXV3pS0uB83TXAkmqd7wvMBuIl9qu4Hfomi9aDM7IlEEn9tumQ==", + "node_modules/@swc/core/node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.2.tgz", + "integrity": "sha512-Eyqipf7ZPGj0vplKHo8JUOoU1un2sg5PjJMpEesX0k+6HKE2T8pdyeyXODN0YTFqzndSa/J43EEPXm+rHAsLFQ==", "cpu": [ "arm" ], @@ -1650,10 +1087,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.107.tgz", - "integrity": "sha512-HWgnn7JORYlOYnGsdunpSF8A+BCZKPLzLtEUA27/M/ZuANcMZabKL9Zurt7XQXq888uJFAt98Gy+59PU90aHKg==", + "node_modules/@swc/core/node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.2.tgz", + "integrity": "sha512-wZn02DH8VYPv3FC0ub4my52Rttsus/rFw+UUfzdb3tHMHXB66LqN+rR0ssIOZrH6K+VLN6qpTw9VizjyoH0BxA==", "cpu": [ "arm64" ], @@ -1666,10 +1103,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.107.tgz", - "integrity": "sha512-vfPF74cWfAm8hyhS8yvYI94ucMHIo8xIYU+oFOW9uvDlGQRgnUf/6DEVbLyt/3yfX5723Ln57U8uiMALbX5Pyw==", + "node_modules/@swc/core/node_modules/@swc/core-linux-arm64-musl": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.2.tgz", + "integrity": "sha512-3G0D5z9hUj9bXNcwmA1eGiFTwe5rWkuL3DsoviTj73TKLpk7u64ND0XjEfO0huVv4vVu9H1jodrKb7nvln/dlw==", "cpu": [ "arm64" ], @@ -1682,10 +1119,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.107.tgz", - "integrity": "sha512-uBVNhIg0ip8rH9OnOsCARUFZ3Mq3tbPHxtmWk9uAa5u8jQwGWeBx5+nTHpDOVd3YxKb6+5xDEI/edeeLpha/9g==", + "node_modules/@swc/core/node_modules/@swc/core-linux-x64-gnu": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.2.tgz", + "integrity": "sha512-LFxn9U8cjmYHw3jrdPNqPAkBGglKE3tCZ8rA7hYyp0BFxuo7L2ZcEnPm4RFpmSCCsExFH+LEJWuMGgWERoktvg==", "cpu": [ "x64" ], @@ -1698,10 +1135,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.107.tgz", - "integrity": "sha512-mvACkUvzSIB12q1H5JtabWATbk3AG+pQgXEN95AmEX2ZA5gbP9+B+mijsg7Sd/3tboHr7ZHLz/q3SHTvdFJrEw==", + "node_modules/@swc/core/node_modules/@swc/core-linux-x64-musl": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.2.tgz", + "integrity": "sha512-dp0fAmreeVVYTUcb4u9njTPrYzKnbIH0EhH2qvC9GOYNNREUu2GezSIDgonjOXkHiTCvopG4xU7y56XtXj4VrQ==", "cpu": [ "x64" ], @@ -1714,10 +1151,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.107.tgz", - "integrity": "sha512-J3P14Ngy/1qtapzbguEH41kY109t6DFxfbK4Ntz9dOWNuVY3o9/RTB841ctnJk0ZHEG+BjfCJjsD2n8H5HcaOA==", + "node_modules/@swc/core/node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.2.tgz", + "integrity": "sha512-HlVIiLMQkzthAdqMslQhDkoXJ5+AOLUSTV6fm6shFKZKqc/9cJvr4S8UveNERL9zUficA36yM3bbfo36McwnvQ==", "cpu": [ "arm64" ], @@ -1730,10 +1167,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.107.tgz", - "integrity": "sha512-ZBUtgyjTHlz8TPJh7kfwwwFma+ktr6OccB1oXC8fMSopD0AxVnQasgun3l3099wIsAB9eEsJDQ/3lDkOLs1gBA==", + "node_modules/@swc/core/node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.2.tgz", + "integrity": "sha512-WCF8faPGjCl4oIgugkp+kL9nl3nUATlzKXCEGFowMEmVVCFM0GsqlmGdPp1pjZoWc9tpYanoXQDnp5IvlDSLhA==", "cpu": [ "ia32" ], @@ -1746,10 +1183,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.107.tgz", - "integrity": "sha512-Eyzo2XRqWOxqhE1gk9h7LWmUf4Bp4Xn2Ttb0ayAXFp6YSTxQIThXcT9kipXZqcpxcmDwoq8iWbbf2P8XL743EA==", + "node_modules/@swc/core/node_modules/@swc/core-win32-x64-msvc": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.2.tgz", + "integrity": "sha512-oV71rwiSpA5xre2C5570BhCsg1HF97SNLsZ/12xv7zayGzqr3yvFALFJN8tHKpqUdCB4FGPjoP3JFdV3i+1wUw==", "cpu": [ "x64" ], @@ -1763,9 +1200,9 @@ } }, "node_modules/@swc/counter": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz", - "integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", "dev": true }, "node_modules/@swc/types": { @@ -1788,28 +1225,6 @@ "node": ">=14.17" } }, - "node_modules/@tufjs/canonical-json": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", - "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", - "dev": true, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@tufjs/models": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.0.tgz", - "integrity": "sha512-c8nj8BaOExmZKO2DXhDfegyhSGcG9E/mPN3U13L+/PsoWm1uaGiHHjxqSHQiasDBQwDA3aHuw9+9spYAP1qvvg==", - "dev": true, - "dependencies": { - "@tufjs/canonical-json": "2.0.0", - "minimatch": "^9.0.3" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, "node_modules/@types/argparse": { "version": "1.0.38", "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", @@ -1958,9 +1373,9 @@ } }, "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/sinon": { @@ -2064,16 +1479,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.1.tgz", - "integrity": "sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.0.tgz", + "integrity": "sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/type-utils": "6.19.1", - "@typescript-eslint/utils": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/type-utils": "7.1.0", + "@typescript-eslint/utils": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -2089,8 +1504,8 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -2098,17 +1513,46 @@ } } }, - "node_modules/@typescript-eslint/parser": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.1.tgz", - "integrity": "sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", + "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/typescript-estree": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", - "debug": "^4.3.4" + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/types": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", + "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.0.tgz", + "integrity": "sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/utils": "7.1.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2118,7 +1562,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -2126,14 +1570,20 @@ } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz", - "integrity": "sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", + "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1" + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2141,18 +1591,67 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.1.tgz", - "integrity": "sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/types": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", + "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", + "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.19.1", - "@typescript-eslint/utils": "6.19.1", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "@typescript-eslint/types": "7.1.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys/node_modules/@typescript-eslint/types": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", + "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.0.tgz", + "integrity": "sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", + "debug": "^4.3.4" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2162,7 +1661,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -2170,10 +1669,27 @@ } } }, - "node_modules/@typescript-eslint/types": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz", - "integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==", + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", + "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", + "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2183,14 +1699,14 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz", - "integrity": "sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==", + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", + "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2211,18 +1727,35 @@ } } }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", + "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.1.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/utils": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.1.tgz", - "integrity": "sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.0.tgz", + "integrity": "sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/typescript-estree": "6.19.1", + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.0", "semver": "^7.5.4" }, "engines": { @@ -2233,16 +1766,91 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz", - "integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", + "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", + "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.1.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", + "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", + "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", + "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.1.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -2303,19 +1911,6 @@ "node": ">= 14" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2438,13 +2033,9 @@ } }, "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-back": { "version": "4.0.2", @@ -2456,13 +2047,16 @@ } }, "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2505,17 +2099,36 @@ "node": ">=8" } }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", - "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "node_modules/array.prototype.filter": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz", + "integrity": "sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz", + "integrity": "sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2561,17 +2174,18 @@ } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", "dev": true, "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", "is-shared-array-buffer": "^1.0.2" }, "engines": { @@ -2613,10 +2227,13 @@ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -2625,15 +2242,48 @@ } }, "node_modules/b4a": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", - "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==" + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==" }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/bare-events": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.0.tgz", + "integrity": "sha512-Yyyqff4PIFfSuthCZqLlPISTWHmnQxoPuAvkmgzsJEmG3CesdIv6Xweayl0JkCZJSB2yYIdJyEz97tpxNhgjbg==", + "optional": true + }, + "node_modules/bare-fs": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.1.5.tgz", + "integrity": "sha512-5t0nlecX+N2uJqdxe9d18A98cp2u9BETelbjKpiVgQqzzmVNFYWEAjQHqS+2Khgto1vcwhik9cXucaj5ve2WWA==", + "optional": true, + "dependencies": { + "bare-events": "^2.0.0", + "bare-os": "^2.0.0", + "bare-path": "^2.0.0", + "streamx": "^2.13.0" + } + }, + "node_modules/bare-os": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.2.0.tgz", + "integrity": "sha512-hD0rOPfYWOMpVirTACt4/nK8mC55La12K5fY1ij8HAdfQakD62M+H4o4tpfKzVGLgRDTuk3vjA4GqGXXCeFbag==", + "optional": true + }, + "node_modules/bare-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.0.tgz", + "integrity": "sha512-DIIg7ts8bdRKwJRJrUMy/PICEaQZaPGZ26lsSx9MJSwIhSrcdHn7/C8W+XmnG/rKi6BaRcz+JO00CjZteybDtw==", + "optional": true, + "dependencies": { + "bare-os": "^2.1.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -2740,15 +2390,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", - "dev": true, - "dependencies": { - "semver": "^7.0.0" - } - }, "node_modules/c8": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/c8/-/c8-9.1.0.tgz", @@ -2815,47 +2456,20 @@ "node": ">=12" } }, - "node_modules/cacache": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", - "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", - "dev": true, - "dependencies": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2953,27 +2567,6 @@ "node": ">= 6" } }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chromium-bidi": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.6.tgz", - "integrity": "sha512-ber8smgoAs4EqSUHRb0I8fpx371ZmvsdQav8HRM9oO4fk5Ox16vQiNYXlsZkRj4FfvVL2dCef+zBFQixp+79CA==", - "dependencies": { - "mitt": "3.0.1", - "urlpattern-polyfill": "10.0.0" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -2989,15 +2582,6 @@ "node": ">=8" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -3063,15 +2647,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/colors": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz", - "integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/command-line-usage": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", @@ -3171,7 +2746,8 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true }, "node_modules/convert-source-map": { "version": "2.0.0", @@ -3201,9 +2777,9 @@ } }, "node_modules/data-uri-to-buffer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.1.tgz", - "integrity": "sha512-MZd3VlchQkp8rdend6vrx7MmVDJzSNTBvghvKjirLkD+WTChA3KUf0jkE68Q4UyctNqI11zZO9/x2Yx+ub5Cvg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", "engines": { "node": ">= 14" } @@ -3295,17 +2871,20 @@ } }, "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-lazy-prop": { @@ -3348,9 +2927,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1232444", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1232444.tgz", - "integrity": "sha512-pM27vqEfxSxRkTMnF+XCmxSEb6duO5R+t8A9DEEJgy4Wz2RVanje2mmj99B6A3zv2r/qGfYlOvYznUhuokizmg==" + "version": "0.0.1249869", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1249869.tgz", + "integrity": "sha512-Ctp4hInA0BEavlUoRy9mhGq0i+JSo/AwVyX2EFgZmV1kYB+Zq+EMBAn52QWu6FbRr10hRb6pBl420upbp4++vg==" }, "node_modules/dezalgo": { "version": "1.0.4", @@ -3463,12 +3042,6 @@ "node": ">=6" } }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true - }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -3478,50 +3051,52 @@ } }, "node_modules/es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.4.tgz", + "integrity": "sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.6", + "call-bind": "^1.0.7", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.2", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", "globalthis": "^1.0.3", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", + "has-property-descriptors": "^1.0.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", + "hasown": "^2.0.1", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", + "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", "object-inspect": "^1.13.1", "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.0", + "safe-regex-test": "^1.0.3", "string.prototype.trim": "^1.2.8", "string.prototype.trimend": "^1.0.7", "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", + "typed-array-buffer": "^1.0.1", "typed-array-byte-length": "^1.0.0", "typed-array-byte-offset": "^1.0.0", "typed-array-length": "^1.0.4", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" + "which-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -3530,15 +3105,42 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" }, "engines": { "node": ">= 0.4" @@ -3571,9 +3173,9 @@ } }, "node_modules/esbuild": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.0.tgz", - "integrity": "sha512-6iwE3Y2RVYCME1jLpBqq7LQWK3MW6vjV2bZy6gt/WrqkY+WE74Spyc0ThAOYpMtITvnjX09CrC6ym7A/m9mebA==", + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz", + "integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==", "dev": true, "hasInstallScript": true, "bin": { @@ -3583,35 +3185,403 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.0", - "@esbuild/android-arm": "0.20.0", - "@esbuild/android-arm64": "0.20.0", - "@esbuild/android-x64": "0.20.0", - "@esbuild/darwin-arm64": "0.20.0", - "@esbuild/darwin-x64": "0.20.0", - "@esbuild/freebsd-arm64": "0.20.0", - "@esbuild/freebsd-x64": "0.20.0", - "@esbuild/linux-arm": "0.20.0", - "@esbuild/linux-arm64": "0.20.0", - "@esbuild/linux-ia32": "0.20.0", - "@esbuild/linux-loong64": "0.20.0", - "@esbuild/linux-mips64el": "0.20.0", - "@esbuild/linux-ppc64": "0.20.0", - "@esbuild/linux-riscv64": "0.20.0", - "@esbuild/linux-s390x": "0.20.0", - "@esbuild/linux-x64": "0.20.0", - "@esbuild/netbsd-x64": "0.20.0", - "@esbuild/openbsd-x64": "0.20.0", - "@esbuild/sunos-x64": "0.20.0", - "@esbuild/win32-arm64": "0.20.0", - "@esbuild/win32-ia32": "0.20.0", - "@esbuild/win32-x64": "0.20.0" + "@esbuild/aix-ppc64": "0.20.1", + "@esbuild/android-arm": "0.20.1", + "@esbuild/android-arm64": "0.20.1", + "@esbuild/android-x64": "0.20.1", + "@esbuild/darwin-arm64": "0.20.1", + "@esbuild/darwin-x64": "0.20.1", + "@esbuild/freebsd-arm64": "0.20.1", + "@esbuild/freebsd-x64": "0.20.1", + "@esbuild/linux-arm": "0.20.1", + "@esbuild/linux-arm64": "0.20.1", + "@esbuild/linux-ia32": "0.20.1", + "@esbuild/linux-loong64": "0.20.1", + "@esbuild/linux-mips64el": "0.20.1", + "@esbuild/linux-ppc64": "0.20.1", + "@esbuild/linux-riscv64": "0.20.1", + "@esbuild/linux-s390x": "0.20.1", + "@esbuild/linux-x64": "0.20.1", + "@esbuild/netbsd-x64": "0.20.1", + "@esbuild/openbsd-x64": "0.20.1", + "@esbuild/sunos-x64": "0.20.1", + "@esbuild/win32-arm64": "0.20.1", + "@esbuild/win32-ia32": "0.20.1", + "@esbuild/win32-x64": "0.20.1" + } + }, + "node_modules/esbuild/node_modules/@esbuild/aix-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.1.tgz", + "integrity": "sha512-m55cpeupQ2DbuRGQMMZDzbv9J9PgVelPjlcmM5kxHnrBdBx6REaEd7LamYV7Dm8N7rCyR/XwU6rVP8ploKtIkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.1.tgz", + "integrity": "sha512-4j0+G27/2ZXGWR5okcJi7pQYhmkVgb4D7UKwxcqrjhvp5TKWx3cUjgB1CGj1mfdmJBQ9VnUGgUhign+FPF2Zgw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.1.tgz", + "integrity": "sha512-hCnXNF0HM6AjowP+Zou0ZJMWWa1VkD77BXe959zERgGJBBxB+sV+J9f/rcjeg2c5bsukD/n17RKWXGFCO5dD5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.1.tgz", + "integrity": "sha512-MSfZMBoAsnhpS+2yMFYIQUPs8Z19ajwfuaSZx+tSl09xrHZCjbeXXMsUF/0oq7ojxYEpsSo4c0SfjxOYXRbpaA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/darwin-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz", + "integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/darwin-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.1.tgz", + "integrity": "sha512-pFIfj7U2w5sMp52wTY1XVOdoxw+GDwy9FsK3OFz4BpMAjvZVs0dT1VXs8aQm22nhwoIWUmIRaE+4xow8xfIDZA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.1.tgz", + "integrity": "sha512-UyW1WZvHDuM4xDz0jWun4qtQFauNdXjXOtIy7SYdf7pbxSWWVlqhnR/T2TpX6LX5NI62spt0a3ldIIEkPM6RHw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/freebsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.1.tgz", + "integrity": "sha512-itPwCw5C+Jh/c624vcDd9kRCCZVpzpQn8dtwoYIt2TJF3S9xJLiRohnnNrKwREvcZYx0n8sCSbvGH349XkcQeg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.1.tgz", + "integrity": "sha512-LojC28v3+IhIbfQ+Vu4Ut5n3wKcgTu6POKIHN9Wpt0HnfgUGlBuyDDQR4jWZUZFyYLiz4RBBBmfU6sNfn6RhLw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz", + "integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz", + "integrity": "sha512-4H/sQCy1mnnGkUt/xszaLlYJVTz3W9ep52xEefGtd6yXDQbz/5fZE5dFLUgsPdbUOQANcVUa5iO6g3nyy5BJiw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-loong64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.1.tgz", + "integrity": "sha512-c0jgtB+sRHCciVXlyjDcWb2FUuzlGVRwGXgI+3WqKOIuoo8AmZAddzeOHeYLtD+dmtHw3B4Xo9wAUdjlfW5yYA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-mips64el": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.1.tgz", + "integrity": "sha512-TgFyCfIxSujyuqdZKDZ3yTwWiGv+KnlOeXXitCQ+trDODJ+ZtGOzLkSWngynP0HZnTsDyBbPy7GWVXWaEl6lhA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.1.tgz", + "integrity": "sha512-b+yuD1IUeL+Y93PmFZDZFIElwbmFfIKLKlYI8M6tRyzE6u7oEP7onGk0vZRh8wfVGC2dZoy0EqX1V8qok4qHaw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-riscv64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.1.tgz", + "integrity": "sha512-wpDlpE0oRKZwX+GfomcALcouqjjV8MIX8DyTrxfyCfXxoKQSDm45CZr9fanJ4F6ckD4yDEPT98SrjvLwIqUCgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-s390x": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.1.tgz", + "integrity": "sha512-5BepC2Au80EohQ2dBpyTquqGCES7++p7G+7lXe1bAIvMdXm4YYcEfZtQrP4gaoZ96Wv1Ute61CEHFU7h4FMueQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.1.tgz", + "integrity": "sha512-5gRPk7pKuaIB+tmH+yKd2aQTRpqlf1E4f/mC+tawIm/CGJemZcHZpp2ic8oD83nKgUPMEd0fNanrnFljiruuyA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/netbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.1.tgz", + "integrity": "sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/openbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.1.tgz", + "integrity": "sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/sunos-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.1.tgz", + "integrity": "sha512-ZnWEyCM0G1Ex6JtsygvC3KUUrlDXqOihw8RicRuQAzw+c4f1D66YlPNNV3rkjVW90zXVsHwZYWbJh3v+oQFM9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.1.tgz", + "integrity": "sha512-QZ6gXue0vVQY2Oon9WyLFCdSuYbXSoxaZrPuJ4c20j6ICedfsDilNPYfHLlMH7vGfU5DQR0czHLmJvH4Nzis/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.1.tgz", + "integrity": "sha512-HzcJa1NcSWTAU0MJIxOho8JftNp9YALui3o+Ny7hCh0v5f90nprly1U3Sj1Ldj/CvKKdvvFsCRvDkpsEMp4DNw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.1.tgz", + "integrity": "sha512-0MBh53o6XtI6ctDnRMeQ+xoCN8kD2qI1rY1KgF/xdWQwoFeKou7puvDfV8/Wv4Ctx2rRpET/gGdz3YlNtNACSA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "engines": { "node": ">=6" } @@ -3648,16 +3618,16 @@ } }, "node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -3944,9 +3914,9 @@ } }, "node_modules/eslint-plugin-mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.2.0.tgz", - "integrity": "sha512-ZhdxzSZnd1P9LqDPF0DBcFLpRIGdh1zkF2JHnQklKQOvrQtT73kdP5K9V2mzvbLR+cCAO9OI48NXK/Ax9/ciCQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.3.0.tgz", + "integrity": "sha512-IWzbg2K6B1Q7h37Ih4zMyW+nhmw1JvUlHlbCUUUu6PfOOAUGCB0gxmvv7/U+TQQ6e8yHUv+q7KMdIIum4bx+PA==", "dev": true, "dependencies": { "eslint-utils": "^3.0.0", @@ -4084,9 +4054,9 @@ } }, "node_modules/eslint-plugin-unused-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.0.0.tgz", - "integrity": "sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.1.0.tgz", + "integrity": "sha512-9l1YFCzXKkw1qtAru1RWUtG2EVDZY0a0eChKXcL+EZ5jitG7qxdctu4RnvhOJHv4xfmUf7h+JJPINlVpGhZMrw==", "dev": true, "dependencies": { "eslint-rule-composer": "^0.3.0" @@ -4095,8 +4065,8 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^6.0.0", - "eslint": "^8.0.0" + "@typescript-eslint/eslint-plugin": "6 - 7", + "eslint": "8" }, "peerDependenciesMeta": { "@typescript-eslint/eslint-plugin": { @@ -4174,6 +4144,15 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4304,12 +4283,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/exponential-backoff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "dev": true - }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -4423,9 +4396,9 @@ } }, "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -4536,9 +4509,9 @@ } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.0.tgz", + "integrity": "sha512-noqGuLw158+DuD9UPRKHpJ2hGxpFyDlYYrfM0mWt4XhT4n0lwzTLh70Tkdyy4kyTmyTT9Bv7bWAJqw7cgkEXDg==", "dev": true }, "node_modules/for-each": { @@ -4579,18 +4552,6 @@ "node": ">=6 <7 || >=8" } }, - "node_modules/fs-minipass": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -4654,16 +4615,20 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "dependencies": { + "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4681,13 +4646,14 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" }, "engines": { "node": ">= 0.4" @@ -4709,51 +4675,49 @@ } }, "node_modules/get-uri": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.2.tgz", - "integrity": "sha512-5KLucCJobh8vBY1K07EFV4+cPZH3mrV9YeAruUseCQKHB58SGjjT2l9/eA9LD082IiuMjSlFJEcdJ27TXvbZNw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", "dependencies": { "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^6.0.0", + "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4", - "fs-extra": "^8.1.0" + "fs-extra": "^11.2.0" }, "engines": { "node": ">= 14" } }, "node_modules/get-uri/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dependencies": { "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=14.14" } }, - "node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "node_modules/get-uri/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" + "universalify": "^2.0.0" }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/get-uri/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 10.0.0" } }, "node_modules/glob-parent": { @@ -5358,21 +5322,21 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.2" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, "engines": { "node": ">= 0.4" @@ -5394,12 +5358,12 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -5409,9 +5373,9 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", "dev": true, "dependencies": { "function-bind": "^1.1.2" @@ -5466,16 +5430,10 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, "node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" @@ -5485,9 +5443,9 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -5537,26 +5495,14 @@ ] }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" } }, - "node_modules/ignore-walk": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", - "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", - "dev": true, - "dependencies": { - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -5657,12 +5603,12 @@ } }, "node_modules/internal-slot": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", - "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.2", + "es-errors": "^1.3.0", "hasown": "^2.0.0", "side-channel": "^1.0.4" }, @@ -5670,10 +5616,17 @@ "node": ">= 0.4" } }, - "node_modules/ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } }, "node_modules/irregular-plurals": { "version": "3.5.0", @@ -5685,14 +5638,16 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5831,16 +5786,10 @@ "node": ">=8" } }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true - }, "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, "engines": { "node": ">= 0.4" @@ -5907,12 +5856,15 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5961,12 +5913,12 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dev": true, "dependencies": { - "which-typed-array": "^1.1.11" + "which-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -6045,9 +5997,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -6177,10 +6129,10 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/js-yaml/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" }, "node_modules/json-buffer": { "version": "3.0.1", @@ -6188,12 +6140,6 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -6226,26 +6172,17 @@ "node_modules/jsonc-parser": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", - "dev": true + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" }, "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ] - }, "node_modules/just-extend": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", @@ -6409,21 +6346,6 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -6481,7 +6403,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -6489,17 +6410,6 @@ "node": ">=10" } }, - "node_modules/magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -6515,32 +6425,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-fetch-happen": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", - "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", - "dev": true, - "dependencies": { - "@npmcli/agent": "^2.0.0", - "cacache": "^18.0.0", - "http-cache-semantics": "^4.1.1", - "is-lambda": "^1.0.1", - "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, "node_modules/make-synchronized": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/make-synchronized/-/make-synchronized-0.2.7.tgz", - "integrity": "sha512-tbTJaNgmKV3E6yYxEN5djObcMt0j1WB2ltn8JteZYczrdFkGMor3KAraPGUf4NJsf5u+FvJbgbGGL35N3J6VVw==", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/make-synchronized/-/make-synchronized-0.2.8.tgz", + "integrity": "sha512-jtXnKYCxjmGaXiZhXbDbGPbh4YyTvIIbOgcQjtAboc4RSm9k3nyhTFvFQB0cfs7QFKuZXKe2D2RvOkv1c+vpxg==", "dev": true, "funding": { "url": "https://github.com/fisker/make-synchronized?sponsor=1" @@ -6710,154 +6598,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/minipass-collect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", - "dev": true, - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/minipass-json-stream/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", @@ -6875,15 +6615,10 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.3.0.tgz", + "integrity": "sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==", "dependencies": { "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", @@ -6892,13 +6627,12 @@ "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.2.0", + "glob": "8.1.0", "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", "minimatch": "5.0.1", "ms": "2.1.3", - "nanoid": "3.3.3", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", @@ -6913,51 +6647,26 @@ }, "engines": { "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" } }, "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mocha/node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/mocha/node_modules/minimatch": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", @@ -6988,14 +6697,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "engines": { - "node": ">=10" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -7007,17 +6708,6 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7039,15 +6729,6 @@ "ncp": "bin/ncp" } }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/netmask": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", @@ -7056,16 +6737,10 @@ "node": ">= 0.4.0" } }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, "node_modules/nise": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.7.tgz", - "integrity": "sha512-wWtNUhkT7k58uvWTB/Gy26eA/EJKtPZFVAhEilN5UYVmmGRYOURbejRUyKm0Uu9XVEW7K5nBOZfR8VMB4QR2RQ==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz", + "integrity": "sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.0", @@ -7094,78 +6769,6 @@ } } }, - "node_modules/node-gyp": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", - "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", - "dev": true, - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^10.3.10", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^13.0.0", - "nopt": "^7.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^4.0.0" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/abbrev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/node-gyp/node_modules/nopt": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", - "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", - "dev": true, - "dependencies": { - "abbrev": "^2.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "dev": true, - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, "node_modules/nopt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", @@ -7202,318 +6805,90 @@ "node": ">=0.10.0" } }, - "node_modules/npm-bundled": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", - "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", - "dev": true, - "dependencies": { - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-bundled/node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-install-checks": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", - "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", - "dev": true, - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/npm-normalize-package-bin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", "dev": true }, - "node_modules/npm-package-arg": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", - "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", - "dev": true, - "dependencies": { - "hosted-git-info": "^7.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-package-arg/node_modules/hosted-git-info": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", - "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "node_modules/npm-run-all2": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-6.1.2.tgz", + "integrity": "sha512-WwwnS8Ft+RpXve6T2EIEVpFLSqN+ORHRvgNk3H9N62SZXjmzKoRhMFg3I17TK3oMaAEr+XFbRirWS2Fn3BCPSg==", "dev": true, "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-package-arg/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/npm-packlist": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", - "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", - "dev": true, - "dependencies": { - "ignore-walk": "^6.0.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-pick-manifest": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz", - "integrity": "sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==", - "dev": true, - "dependencies": { - "npm-install-checks": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "npm-package-arg": "^11.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-pick-manifest/node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-registry-fetch": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.1.0.tgz", - "integrity": "sha512-PQCELXKt8Azvxnt5Y85GseQDJJlglTFM9L9U9gkv2y4e9s0k3GVDdOx3YoB6gm2Do0hlkzC39iCGXby+Wve1Bw==", - "dev": true, - "dependencies": { - "make-fetch-happen": "^13.0.0", - "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^11.0.0", - "proc-log": "^3.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", + "ansi-styles": "^6.2.1", + "cross-spawn": "^7.0.3", "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" + "minimatch": "^9.0.0", + "pidtree": "^0.6.0", + "read-package-json-fast": "^3.0.2", + "shell-quote": "^1.7.3" }, "bin": { "npm-run-all": "bin/npm-run-all/index.js", + "npm-run-all2": "bin/npm-run-all/index.js", "run-p": "bin/run-p/index.js", "run-s": "bin/run-s/index.js" }, "engines": { - "node": ">= 4" + "node": "^14.18.0 || >=16.0.0", + "npm": ">= 8" } }, - "node_modules/npm-run-all/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/npm-run-all/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/npm-run-all2/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/npm-run-all/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/npm-run-all/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "node": ">=12" }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/npm-run-all/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/npm-run-all/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/npm-run-all/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/npm-run-all2/node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" + "bin": { + "pidtree": "bin/pidtree.js" }, "engines": { - "node": "*" - } - }, - "node_modules/npm-run-all/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" + "node": ">=0.10" } }, - "node_modules/npm-run-all/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "node_modules/npm-run-all2/node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", "dev": true, "dependencies": { - "shebang-regex": "^1.0.0" + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm-run-all/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "node_modules/npm-run-all2/node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm-run-all/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/npm-run-all2/node_modules/read-package-json-fast/node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-run-path": { @@ -7597,15 +6972,16 @@ } }, "node_modules/object.groupby": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", - "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.2.tgz", + "integrity": "sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1" + "array.prototype.filter": "^1.0.3", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.0.0" } }, "node_modules/object.values": { @@ -7760,21 +7136,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -7803,12 +7164,11 @@ } }, "node_modules/pac-resolver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", - "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", "dependencies": { "degenerator": "^5.0.0", - "ip": "^1.1.8", "netmask": "^2.0.2" }, "engines": { @@ -7826,19 +7186,6 @@ "node": ">=6" } }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/parse-ms": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-3.0.0.tgz", @@ -7869,6 +7216,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -7903,9 +7251,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "engines": { "node": "14 || >=16.14" } @@ -7947,27 +7295,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/pixelmatch": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.3.0.tgz", @@ -8025,6 +7352,15 @@ "node": ">=14.19.0" } }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -8035,9 +7371,9 @@ } }, "node_modules/prettier": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.4.tgz", - "integrity": "sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -8102,15 +7438,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -8119,25 +7446,6 @@ "node": ">=0.4.0" } }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/proper-lockfile": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", @@ -8156,14 +7464,14 @@ "dev": true }, "node_modules/proxy-agent": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", - "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", "dependencies": { "agent-base": "^7.0.2", "debug": "^4.3.4", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", "lru-cache": "^7.14.1", "pac-proxy-agent": "^7.0.1", "proxy-from-env": "^1.1.0", @@ -8303,37 +7611,6 @@ "npm-normalize-package-bin": "^1.0.0" } }, - "node_modules/read-package-json-fast": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", - "dev": true, - "dependencies": { - "json-parse-even-better-errors": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", - "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-package-json-fast/node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/read-package-json/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -8403,20 +7680,6 @@ "semver": "bin/semver" } }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/read-pkg-up": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", @@ -8564,45 +7827,6 @@ "node": ">=8" } }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -8663,14 +7887,15 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" }, "engines": { "node": ">= 0.4" @@ -8938,13 +8163,13 @@ ] }, "node_modules/safe-regex-test": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", - "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", "is-regex": "^1.1.4" }, "engines": { @@ -8961,10 +8186,9 @@ "devOptional": true }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -8984,14 +8208,15 @@ } }, "node_modules/set-function-length": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", - "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", + "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", "dev": true, "dependencies": { - "define-data-property": "^1.1.1", + "define-data-property": "^1.1.2", + "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.2", + "get-intrinsic": "^1.2.3", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.1" }, @@ -9000,14 +8225,15 @@ } }, "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, "dependencies": { - "define-data-property": "^1.0.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -9042,14 +8268,18 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", + "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9066,23 +8296,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/sigstore": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.2.0.tgz", - "integrity": "sha512-fcU9clHwEss2/M/11FFM8Jwc4PjBgbhXoNskoK5guoK0qGQBSeUbQZRJ+B2fDFIvhyf0gqCaPrel9mszbhAxug==", - "dev": true, - "dependencies": { - "@sigstore/bundle": "^2.1.1", - "@sigstore/core": "^0.2.0", - "@sigstore/protobuf-specs": "^0.2.1", - "@sigstore/sign": "^2.2.1", - "@sigstore/tuf": "^2.3.0", - "@sigstore/verify": "^0.1.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, "node_modules/sinon": { "version": "17.0.1", "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", @@ -9102,9 +8315,9 @@ } }, "node_modules/sinon/node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, "engines": { "node": ">=0.3.1" @@ -9138,15 +8351,15 @@ } }, "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.3.tgz", + "integrity": "sha512-vfuYK48HXCTFD03G/1/zkIls3Ebr2YNa4qU9gHDZdblHLiqhJrJGkY3+0Nx0JpN9qBhJbVObc1CNciT1bIZJxw==", "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, @@ -9163,11 +8376,6 @@ "node": ">= 14" } }, - "node_modules/socks/node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -9209,9 +8417,9 @@ } }, "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true }, "node_modules/spdx-expression-parse": { @@ -9225,9 +8433,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", "dev": true }, "node_modules/spdx-ranges": { @@ -9248,22 +8456,9 @@ } }, "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/ssri": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", - "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" }, "node_modules/stack-utils": { "version": "2.0.6", @@ -9287,12 +8482,15 @@ } }, "node_modules/streamx": { - "version": "2.15.6", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.6.tgz", - "integrity": "sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz", + "integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==", "dependencies": { "fast-fifo": "^1.1.0", "queue-tick": "^1.0.1" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" } }, "node_modules/string_decoder": { @@ -9339,23 +8537,6 @@ "node": ">=8" } }, - "node_modules/string.prototype.padend": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.5.tgz", - "integrity": "sha512-DOB27b/2UTTD+4myKUFh+/fXWcu/UDyASIXfg+7VzoCNNGOfWvoyU/x5pvVHr++ztyt/oSYI1BcWBBG/hmlNjA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/string.prototype.trim": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", @@ -9559,31 +8740,17 @@ "node": ">=6" } }, - "node_modules/tar": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", - "dev": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/tar-fs": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", - "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz", + "integrity": "sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==", "dependencies": { - "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^2.1.1", + "bare-path": "^2.1.0" } }, "node_modules/tar-stream": { @@ -9596,51 +8763,6 @@ "streamx": "^2.15.0" } }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -9755,12 +8877,12 @@ } }, "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", + "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", "dev": true, "engines": { - "node": ">=16.13.0" + "node": ">=16" }, "peerDependencies": { "typescript": ">=4.2.0" @@ -9791,9 +8913,9 @@ } }, "node_modules/tsd": { - "version": "0.30.4", - "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.30.4.tgz", - "integrity": "sha512-ncC4SwAeUk0OTcXt5h8l0/gOLHJSp9ogosvOADT6QYzrl0ITm398B3wkz8YESqefIsEEwvYAU8bvo7/rcN/M0Q==", + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.30.7.tgz", + "integrity": "sha512-oTiJ28D6B/KXoU3ww/Eji+xqHJojiuPVMwA12g4KYX1O72N93Nb6P3P3h2OAhhf92Xl8NIhb/xFmBZd5zw/xUw==", "dev": true, "dependencies": { "@tsd/typescript": "~5.3.3", @@ -9833,9 +8955,9 @@ } }, "node_modules/tsx": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.0.tgz", - "integrity": "sha512-I+t79RYPlEYlHn9a+KzwrvEwhJg35h/1zHsLC2JXvhC2mdynMv6Zxzvhv5EMV6VF5qJlLlkSnMVvdZV3PSIGcg==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.1.tgz", + "integrity": "sha512-8d6VuibXHtlN5E3zFkgY8u4DX7Y3Z27zvvPKVmLon/D4AjuKzarkUBTLDBgj9iTQ0hg5xM7c/mYiRVM+HETf0g==", "dev": true, "dependencies": { "esbuild": "~0.19.10", @@ -10257,20 +9379,6 @@ "@esbuild/win32-x64": "0.19.12" } }, - "node_modules/tuf-js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.0.tgz", - "integrity": "sha512-ZSDngmP1z6zw+FIkIBjvOp/II/mIub/O7Pp12j1WNsiCpg5R5wAc//i555bBQsE44O94btLt0xM/Zr2LQjwdCg==", - "dev": true, - "dependencies": { - "@tufjs/models": "2.0.0", - "debug": "^4.3.4", - "make-fetch-happen": "^13.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -10314,29 +9422,30 @@ } }, "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" } }, "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -10346,16 +9455,17 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -10365,14 +9475,20 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz", + "integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10425,9 +9541,9 @@ } }, "node_modules/undici": { - "version": "5.28.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz", - "integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==", + "version": "5.28.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", + "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", "dev": true, "dependencies": { "@fastify/busboy": "^2.0.0" @@ -10442,34 +9558,11 @@ "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", "devOptional": true }, - "node_modules/unique-filename": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", - "dev": true, - "dependencies": { - "unique-slug": "^4.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/unique-slug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, "engines": { "node": ">= 4.0.0" } @@ -10531,18 +9624,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "node_modules/validate-npm-package-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", - "dev": true, - "dependencies": { - "builtins": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/validator": { "version": "13.11.0", "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", @@ -10605,16 +9686,16 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", + "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", + "available-typed-arrays": "^1.0.6", + "call-bind": "^1.0.5", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "has-tostringtag": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -10748,8 +9829,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { "version": "16.2.0", @@ -10769,9 +9849,9 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", "engines": { "node": ">=10" } @@ -10871,14 +9951,15 @@ }, "packages/browsers": { "name": "@puppeteer/browsers", - "version": "1.9.1", + "version": "2.1.0", "license": "Apache-2.0", "dependencies": { "debug": "4.3.4", "extract-zip": "2.0.1", "progress": "2.0.3", - "proxy-agent": "6.3.1", - "tar-fs": "3.0.4", + "proxy-agent": "6.4.0", + "semver": "7.6.0", + "tar-fs": "3.0.5", "unbzip2-stream": "1.4.3", "yargs": "17.7.2" }, @@ -10893,7 +9974,7 @@ "@types/yargs": "17.0.32" }, "engines": { - "node": ">=16.3.0" + "node": ">=18" } }, "packages/browsers/node_modules/cliui": { @@ -10933,26 +10014,27 @@ }, "packages/ng-schematics": { "name": "@puppeteer/ng-schematics", - "version": "0.5.6", + "version": "0.6.0", "license": "Apache-2.0", "dependencies": { - "@angular-devkit/architect": "^0.1701.1", - "@angular-devkit/core": "^17.0.7", - "@angular-devkit/schematics": "^17.0.7" + "@angular-devkit/architect": "0.1702.2", + "@angular-devkit/core": "17.2.2", + "@angular-devkit/schematics": "17.2.2" }, "devDependencies": { - "@angular/cli": "^17.0.7", - "@schematics/angular": "^17.0.7" + "@angular/cli": "17.2.2", + "@schematics/angular": "17.2.2" }, "engines": { - "node": ">=16.13.2" + "node": ">=18" } }, "packages/ng-schematics/node_modules/@angular-devkit/architect": { - "version": "0.1700.6", - "license": "MIT", + "version": "0.1702.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1702.2.tgz", + "integrity": "sha512-qBvif8/NquFUqVQgs4U+8wXh/rQZv+YlYwg6eDZly1bIaTd/k9spko/seTtNT1OpK/Be+GLo5IbiQ7i2SON3iQ==", "dependencies": { - "@angular-devkit/core": "17.0.6", + "@angular-devkit/core": "17.2.2", "rxjs": "7.8.1" }, "engines": { @@ -10962,13 +10044,14 @@ } }, "packages/ng-schematics/node_modules/@angular-devkit/core": { - "version": "17.0.6", - "license": "MIT", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.2.2.tgz", + "integrity": "sha512-bKMi6bBkEeN4a3qTxCykhrAvE0ESHhKO38Qh1bN/8QSyvKVAEyVAVls5W9IN5GKRHvXgEn9aw+DSzRnPpy9nyw==", "dependencies": { "ajv": "8.12.0", "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.0", - "picomatch": "3.0.1", + "jsonc-parser": "3.2.1", + "picomatch": "4.0.1", "rxjs": "7.8.1", "source-map": "0.7.4" }, @@ -10986,13 +10069,25 @@ } } }, + "packages/ng-schematics/node_modules/@angular-devkit/core/node_modules/picomatch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", + "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "packages/ng-schematics/node_modules/@angular-devkit/schematics": { - "version": "17.0.6", - "license": "MIT", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.2.2.tgz", + "integrity": "sha512-t6dBhHvto9BEIo+Kew0+YyIS3TV1SEd4MActUk+zF4NNQyJ8wRUHL+8glUKB6ZWPyCTYSinJ+QKn/3yytELTHg==", "dependencies": { - "@angular-devkit/core": "17.0.6", - "jsonc-parser": "3.2.0", - "magic-string": "0.30.5", + "@angular-devkit/core": "17.2.2", + "jsonc-parser": "3.2.1", + "magic-string": "0.30.7", "ora": "5.4.1", "rxjs": "7.8.1" }, @@ -11002,27 +10097,39 @@ "yarn": ">= 1.13.0" } }, + "packages/ng-schematics/node_modules/@angular-devkit/schematics/node_modules/magic-string": { + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz", + "integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, "packages/ng-schematics/node_modules/@angular/cli": { - "version": "17.0.6", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-17.2.2.tgz", + "integrity": "sha512-cGGOnOTjU1bHBAU+5LMR1vfjUSmIY204pUcRAHu6xq1Qp8jm0Wf1lYOG1KrzpDezKa8d0WZe6FIVlxsCZRRYSw==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1700.6", - "@angular-devkit/core": "17.0.6", - "@angular-devkit/schematics": "17.0.6", - "@schematics/angular": "17.0.6", + "@angular-devkit/architect": "0.1702.2", + "@angular-devkit/core": "17.2.2", + "@angular-devkit/schematics": "17.2.2", + "@schematics/angular": "17.2.2", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "ini": "4.1.1", - "inquirer": "9.2.11", - "jsonc-parser": "3.2.0", + "inquirer": "9.2.14", + "jsonc-parser": "3.2.1", "npm-package-arg": "11.0.1", "npm-pick-manifest": "9.0.0", "open": "8.4.2", "ora": "5.4.1", - "pacote": "17.0.4", + "pacote": "17.0.6", "resolve": "1.22.8", - "semver": "7.5.4", + "semver": "7.6.0", "symbol-observable": "4.0.0", "yargs": "17.7.2" }, @@ -11035,47 +10142,49 @@ "yarn": ">= 1.13.0" } }, - "packages/ng-schematics/node_modules/@schematics/angular": { - "version": "17.0.6", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/inquirer": { + "version": "9.2.14", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.14.tgz", + "integrity": "sha512-4ByIMt677Iz5AvjyKrDpzaepIyMewNvDcvwpVVRZNmy9dLakVoVgdCHZXbK1SlVJra1db0JZ6XkJyHsanpdrdQ==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/core": "17.0.6", - "@angular-devkit/schematics": "17.0.6", - "jsonc-parser": "3.2.0" + "@ljharb/through": "^2.3.12", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", + "cli-cursor": "^3.1.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "figures": "^3.2.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=18" } }, - "packages/ng-schematics/node_modules/ajv": { - "version": "8.12.0", - "license": "MIT", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/inquirer/node_modules/@ljharb/through": { + "version": "2.3.12", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.12.tgz", + "integrity": "sha512-ajo/heTlG3QgC8EGP6APIejksVAYt4ayz4tqoP3MolFELzcH1x1fzwEYRJTPO0IELutZ5HQ0c26/GqAYy79u3g==", + "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "call-bind": "^1.0.5" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "packages/ng-schematics/node_modules/ansi-colors": { - "version": "4.1.3", - "dev": true, - "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 0.4" } }, - "packages/ng-schematics/node_modules/chalk": { + "packages/ng-schematics/node_modules/@angular/cli/node_modules/inquirer/node_modules/chalk": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, - "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -11083,73 +10192,382 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "packages/ng-schematics/node_modules/cli-width": { + "packages/ng-schematics/node_modules/@angular/cli/node_modules/inquirer/node_modules/cli-width": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, - "license": "ISC", "engines": { "node": ">= 12" } }, - "packages/ng-schematics/node_modules/cliui": { - "version": "8.0.1", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/inquirer/node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, "engines": { - "node": ">=12" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/inquirer/node_modules/run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/inquirer/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=10" + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-package-arg": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", + "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/escape-string-regexp": { + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-package-arg/node_modules/hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-package-arg/node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-package-arg/node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-package-arg/node_modules/validate-npm-package-name": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", "dev": true, - "license": "MIT", + "dependencies": { + "builtins": "^5.0.0" + }, "engines": { - "node": ">=12" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-package-arg/node_modules/validate-npm-package-name/node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-pick-manifest": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz", + "integrity": "sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==", + "dev": true, + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-pick-manifest/node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-pick-manifest/node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote": { + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz", + "integrity": "sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==", + "dev": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/git": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.4.tgz", + "integrity": "sha512-nr6/WezNzuYUppzXRaYu/W4aT5rLxdXqEFupbh6e/ovlYFQ8hpu1UUPV3Ir/YTl+74iXl2ZOMlGzudh9ZPUchQ==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/git/node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/git/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/git/node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" } }, - "packages/ng-schematics/node_modules/figures": { + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dev": true, + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/installed-package-contents/node_modules/npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/installed-package-contents/node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/promise-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.1.tgz", + "integrity": "sha512-P4KkF9jX3y+7yFUxgcUdDtLy+t4OlDGuEBLNs57AZsfSfg+uV6MLndqGpnl4831ggaEdXwR50XFoZP4VFtHolg==", + "dev": true, + "dependencies": { + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/promise-spawn/node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", + "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/@npmcli/package-json": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.0.0.tgz", + "integrity": "sha512-OI2zdYBLhQ7kpNPaJxiflofYIpkNLi+lnGdzqUOfRmCF3r2l1nadcjtCYMJKv/Utm/ZtlffaUuTiAktPHbc17g==", + "dev": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/@npmcli/package-json/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dev": true, - "license": "MIT", "dependencies": { - "escape-string-regexp": "^5.0.0", - "is-unicode-supported": "^1.2.0" + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=14" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "packages/ng-schematics/node_modules/hosted-git-info": { + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/@npmcli/package-json/node_modules/hosted-git-info": { "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^10.0.1" }, @@ -11157,78 +10575,885 @@ "node": "^16.14.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/inquirer": { - "version": "9.2.11", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/@npmcli/package-json/node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/@npmcli/package-json/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/@npmcli/package-json/node_modules/normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", "dev": true, - "license": "MIT", "dependencies": { - "@ljharb/through": "^2.3.9", - "ansi-escapes": "^4.3.2", - "chalk": "^5.3.0", - "cli-cursor": "^3.1.0", - "cli-width": "^4.1.0", - "external-editor": "^3.1.0", - "figures": "^5.0.0", - "lodash": "^4.17.21", - "mute-stream": "1.0.0", - "ora": "^5.4.1", - "run-async": "^3.0.0", - "rxjs": "^7.8.1", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0" + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" }, "engines": { - "node": ">=14.18.0" + "node": "^16.14.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/is-unicode-supported": { - "version": "1.3.0", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", + "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", "dev": true, - "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, "engines": { - "node": ">=12" + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "dev": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/@npmcli/agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.1.tgz", + "integrity": "sha512-H4FrOVtNyWC8MUwL3UfjOsAihHvT1Pe8POj3JvjXhSTJipsZMtgUALCT4mGyYZNxymkUfOw3PUj6dE4QPp6osQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/nopt": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", + "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "dev": true, + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/nopt/node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", + "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/ng-schematics/node_modules/json-parse-even-better-errors": { - "version": "3.0.1", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/p-map/node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, - "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/p-map/node_modules/aggregate-error/node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/json-schema-traverse": { - "version": "1.0.0", - "license": "MIT" + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/unique-filename/node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "packages/ng-schematics/node_modules/jsonc-parser": { - "version": "3.2.0", - "license": "MIT" + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "packages/ng-schematics/node_modules/lru-cache": { - "version": "10.1.0", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-packlist": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", + "dev": true, + "dependencies": { + "ignore-walk": "^6.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-packlist/node_modules/ignore-walk": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", + "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", + "dev": true, + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.1.0.tgz", + "integrity": "sha512-PQCELXKt8Azvxnt5Y85GseQDJJlglTFM9L9U9gkv2y4e9s0k3GVDdOx3YoB6gm2Do0hlkzC39iCGXby+Wve1Bw==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "dev": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/@npmcli/agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.1.tgz", + "integrity": "sha512-H4FrOVtNyWC8MUwL3UfjOsAihHvT1Pe8POj3JvjXhSTJipsZMtgUALCT4mGyYZNxymkUfOw3PUj6dE4QPp6osQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "dev": true, - "license": "ISC", "engines": { "node": "14 || >=16.14" } }, - "packages/ng-schematics/node_modules/mute-stream": { - "version": "1.0.0", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "dev": true, - "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minipass-fetch/node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minipass-fetch/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "packages/ng-schematics/node_modules/normalize-package-data": { + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minipass-json-stream/node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/promise-retry/node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.0.tgz", + "integrity": "sha512-uL4Z10OKV4p6vbdvIXB+OzhInYtIozl/VxUBPgNkBuUi2DeRonnuspmaVAMcrkmfjKGNmRndyQAbE7/AmzGwFg==", + "dev": true, + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json-fast/node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json/node_modules/normalize-package-data": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^7.0.0", "is-core-module": "^2.8.1", @@ -11239,77 +11464,704 @@ "node": "^16.14.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/npm-normalize-package-bin": { + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json/node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json/node_modules/normalize-package-data/node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json/node_modules/npm-normalize-package-bin": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/pacote": { - "version": "17.0.4", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.2.2.tgz", + "integrity": "sha512-2A3WvXkQurhuMgORgT60r6pOWiCOO5LlEqY2ADxGBDGVYLSo5HN0uLtb68YpVpuL/Vi8mLTe7+0Dx2Fq8lLqEg==", "dev": true, - "license": "ISC", "dependencies": { - "@npmcli/git": "^5.0.0", - "@npmcli/installed-package-contents": "^2.0.1", - "@npmcli/promise-spawn": "^7.0.0", - "@npmcli/run-script": "^7.0.0", + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0", + "@sigstore/sign": "^2.2.3", + "@sigstore/tuf": "^2.3.1", + "@sigstore/verify": "^1.1.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/bundle": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.2.0.tgz", + "integrity": "sha512-5VI58qgNs76RDrwXNhpmyN/jKpq9evV/7f1XrcqcAfvxDl5SeVY/I5Rmfe96ULAV7/FK5dge9RBKGBJPhL1WsQ==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.0.0.tgz", + "integrity": "sha512-dW2qjbWLRKGu6MIDUTBuJwXCnR8zivcSpf5inUzk7y84zqy/dji0/uahppoIgMoKeR+6pUZucrwHfkQQtiG9Rw==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/protobuf-specs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.0.tgz", + "integrity": "sha512-zxiQ66JFOjVvP9hbhGj/F/qNdsZfkGb/dVXSanNRNuAzMlr4MC95voPUBX8//ZNnmv3uSYzdfR/JSkrgvZTGxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.3.tgz", + "integrity": "sha512-LqlA+ffyN02yC7RKszCdMTS6bldZnIodiox+IkT8B2f8oRYXCB3LQ9roXeiEL21m64CVH1wyveYAORfD65WoSw==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "dev": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", - "fs-minipass": "^3.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", "minipass": "^7.0.2", - "npm-package-arg": "^11.0.0", - "npm-packlist": "^8.0.0", - "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^16.0.0", - "proc-log": "^3.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", "promise-retry": "^2.0.1", - "read-package-json": "^7.0.0", - "read-package-json-fast": "^3.0.0", - "sigstore": "^2.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11" + "ssri": "^10.0.0" }, - "bin": { - "pacote": "lib/bin.js" + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/@npmcli/agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.1.tgz", + "integrity": "sha512-H4FrOVtNyWC8MUwL3UfjOsAihHvT1Pe8POj3JvjXhSTJipsZMtgUALCT4mGyYZNxymkUfOw3PUj6dE4QPp6osQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/picomatch": { - "version": "3.0.1", - "license": "MIT", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.1.tgz", + "integrity": "sha512-9Iv40z652td/QbV0o5n/x25H9w6IYRt2pIGbTX55yFDYlApDQn/6YZomjz6+KBx69rXHLzHcbtTS586mDdFD+Q==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.0", + "tuf-js": "^2.2.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.0.tgz", + "integrity": "sha512-ZSDngmP1z6zw+FIkIBjvOp/II/mIub/O7Pp12j1WNsiCpg5R5wAc//i555bBQsE44O94btLt0xM/Zr2LQjwdCg==", + "dev": true, + "dependencies": { + "@tufjs/models": "2.0.0", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/@tufjs/models": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.0.tgz", + "integrity": "sha512-c8nj8BaOExmZKO2DXhDfegyhSGcG9E/mPN3U13L+/PsoWm1uaGiHHjxqSHQiasDBQwDA3aHuw9+9spYAP1qvvg==", + "dev": true, + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/@tufjs/models/node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "dev": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/@npmcli/agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.1.tgz", + "integrity": "sha512-H4FrOVtNyWC8MUwL3UfjOsAihHvT1Pe8POj3JvjXhSTJipsZMtgUALCT4mGyYZNxymkUfOw3PUj6dE4QPp6osQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/verify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.1.0.tgz", + "integrity": "sha512-1fTqnqyTBWvV7cftUUFtDcHPdSox0N3Ub7C0lRyReYx4zZUlNTZjCV+HPy4Lre+r45dV7Qx5JLKvqqsgxuyYfg==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, "engines": { "node": ">=10" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "packages/ng-schematics/node_modules/@schematics/angular": { + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.2.2.tgz", + "integrity": "sha512-Q3VAQ/S4gj8D1JPWgWG4enDdDZUu8mUXWVRG1rOi4sHgOF5zgPieQFp3LXqMUgOncmzbXrctkbO6NKc4N2FAag==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "17.2.2", + "@angular-devkit/schematics": "17.2.2", + "jsonc-parser": "3.2.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "packages/ng-schematics/node_modules/ajv": { + "version": "8.12.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "packages/ng-schematics/node_modules/read-package-json": { - "version": "7.0.0", + "packages/ng-schematics/node_modules/ansi-colors": { + "version": "4.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "packages/ng-schematics/node_modules/cliui": { + "version": "8.0.1", "dev": true, "license": "ISC", "dependencies": { - "glob": "^10.2.2", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=12" } }, - "packages/ng-schematics/node_modules/run-async": { - "version": "3.0.0", + "packages/ng-schematics/node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">=0.12.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "packages/ng-schematics/node_modules/json-schema-traverse": { + "version": "1.0.0", + "license": "MIT" + }, "packages/ng-schematics/node_modules/rxjs": { "version": "7.8.1", "license": "Apache-2.0", @@ -11328,19 +12180,6 @@ "version": "2.6.2", "license": "0BSD" }, - "packages/ng-schematics/node_modules/wrap-ansi": { - "version": "6.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, "packages/ng-schematics/node_modules/yargs": { "version": "17.7.2", "dev": true, @@ -11367,13 +12206,13 @@ } }, "packages/puppeteer": { - "version": "21.10.0", + "version": "22.4.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "1.9.1", + "@puppeteer/browsers": "2.1.0", "cosmiconfig": "9.0.0", - "puppeteer-core": "21.10.0" + "puppeteer-core": "22.4.0" }, "bin": { "puppeteer": "lib/esm/puppeteer/node/cli.js" @@ -11382,18 +12221,18 @@ "@types/node": "18.17.15" }, "engines": { - "node": ">=16.13.2" + "node": ">=18" } }, "packages/puppeteer-core": { - "version": "21.10.0", + "version": "22.4.0", "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "1.9.1", - "chromium-bidi": "0.5.6", + "@puppeteer/browsers": "2.1.0", + "chromium-bidi": "0.5.12", "cross-fetch": "4.0.0", "debug": "4.3.4", - "devtools-protocol": "0.0.1232444", + "devtools-protocol": "0.0.1249869", "ws": "8.16.0" }, "devDependencies": { @@ -11405,7 +12244,7 @@ "rxjs": "7.8.1" }, "engines": { - "node": ">=16.13.2" + "node": ">=18" } }, "packages/puppeteer-core/node_modules/@types/node": { @@ -11413,6 +12252,18 @@ "dev": true, "license": "MIT" }, + "packages/puppeteer-core/node_modules/chromium-bidi": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.12.tgz", + "integrity": "sha512-sZMgEBWKbupD0Q7lyFu8AWkrE+rs5ycE12jFkGwIgD/VS8lDPtelPlXM7LYaq4zrkZ/O2L3f4afHUHL0ICdKog==", + "dependencies": { + "mitt": "3.0.1", + "urlpattern-polyfill": "10.0.0" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, "packages/puppeteer-core/node_modules/rxjs": { "version": "7.8.1", "dev": true, @@ -11487,7 +12338,7 @@ "name": "@puppeteer-test/test", "version": "latest", "dependencies": { - "diff": "5.1.0", + "diff": "5.2.0", "jpeg-js": "0.4.4", "pixelmatch": "5.3.0", "pngjs": "7.0.0" @@ -11503,26 +12354,46 @@ "version": "latest", "dependencies": { "glob": "10.3.10", - "mocha": "10.2.0" + "mocha": "10.3.0" } }, "test/node_modules/diff": { - "version": "5.1.0", + "version": "5.2.0", "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, + "test/node_modules/glob": { + "version": "10.3.10", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "tools/docgen": { "name": "@puppeteer/docgen", "version": "0.1.0", "license": "Apache-2.0", "devDependencies": { - "@microsoft/api-documenter": "7.23.20", - "@microsoft/api-extractor": "7.39.4", - "@microsoft/api-extractor-model": "7.28.7", + "@microsoft/api-documenter": "7.23.35", + "@microsoft/api-extractor": "7.42.2", + "@microsoft/api-extractor-model": "7.28.13", "@microsoft/tsdoc": "0.14.2", - "@rushstack/node-core-library": "3.64.2" + "@rushstack/node-core-library": "4.0.2" } }, "tools/doctest": { @@ -11533,7 +12404,7 @@ "doctest": "bin/doctest.js" }, "devDependencies": { - "@swc/core": "1.3.107", + "@swc/core": "1.4.2", "@types/doctrine": "0.0.9", "@types/source-map-support": "0.5.10", "@types/yargs": "17.0.32", @@ -11559,6 +12430,27 @@ "node": ">=12" } }, + "tools/doctest/node_modules/glob": { + "version": "10.3.10", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "tools/doctest/node_modules/source-map": { "version": "0.7.4", "dev": true, @@ -11597,7 +12489,8 @@ "version": "0.1.0", "license": "Apache-2.0", "devDependencies": { - "@prettier/sync": "0.5.0" + "@prettier/sync": "0.5.1", + "@typescript-eslint/utils": "7.1.0" } }, "tools/mocha-runner": { @@ -11628,6 +12521,27 @@ "node": ">=12" } }, + "tools/mocha-runner/node_modules/glob": { + "version": "10.3.10", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "tools/mocha-runner/node_modules/yargs": { "version": "17.7.2", "dev": true, diff --git a/remote/test/puppeteer/package.json b/remote/test/puppeteer/package.json index 612f5ac369..0ffdceedf7 100644 --- a/remote/test/puppeteer/package.json +++ b/remote/test/puppeteer/package.json @@ -32,7 +32,7 @@ "test:chrome:bidi-local": "wireit", "test:chrome:headful": "wireit", "test:chrome:headless": "wireit", - "test:chrome:new-headless": "wireit", + "test:chrome:shell": "wireit", "test:firefox": "wireit", "test:firefox:bidi": "wireit", "test:firefox:bidi:headful": "wireit", @@ -50,7 +50,8 @@ "./packages/puppeteer:build", "./packages/testserver:build", "./test:build", - "./test/installation:build" + "./test/installation:build", + "build:tools" ] }, "build:tools": { @@ -83,7 +84,7 @@ "test:chrome:bidi", "test:chrome:headful", "test:chrome:headless", - "test:chrome:new-headless" + "test:chrome:shell" ] }, "test:chrome:bidi": { @@ -98,8 +99,8 @@ "test:chrome:headless": { "command": "npm test -- --test-suite chrome-headless" }, - "test:chrome:new-headless": { - "command": "npm test -- --test-suite chrome-new-headless" + "test:chrome:shell": { + "command": "npm test -- --test-suite chrome-headless-shell" }, "test:firefox:bidi": { "command": "npm test -- --test-suite firefox-bidi" @@ -139,34 +140,34 @@ "@actions/core": "1.10.1", "@types/mocha": "10.0.6", "@types/node": "20.8.4", - "@types/semver": "7.5.6", + "@types/semver": "7.5.8", "@types/sinon": "17.0.3", - "@typescript-eslint/eslint-plugin": "6.19.1", - "@typescript-eslint/parser": "6.19.1", - "esbuild": "0.20.0", + "@typescript-eslint/eslint-plugin": "7.1.0", + "@typescript-eslint/parser": "7.1.0", + "esbuild": "0.20.1", "eslint-config-prettier": "9.1.0", "eslint-import-resolver-typescript": "3.6.1", "eslint-plugin-import": "2.29.1", - "eslint-plugin-mocha": "10.2.0", + "eslint-plugin-mocha": "10.3.0", "eslint-plugin-prettier": "5.1.3", "eslint-plugin-rulesdir": "0.2.2", "eslint-plugin-tsdoc": "0.2.17", - "eslint-plugin-unused-imports": "3.0.0", - "eslint": "8.56.0", + "eslint-plugin-unused-imports": "3.1.0", + "eslint": "8.57.0", "execa": "8.0.1", "expect": "29.7.0", "gts": "5.2.0", "hereby": "1.8.9", "license-checker": "25.0.1", - "mocha": "10.2.0", - "npm-run-all": "4.1.5", - "prettier": "3.2.4", - "semver": "7.5.4", + "mocha": "10.3.0", + "npm-run-all2": "6.1.2", + "prettier": "3.2.5", + "semver": "7.6.0", "sinon": "17.0.1", "source-map-support": "0.5.21", "spdx-satisfies": "5.0.1", - "tsd": "0.30.4", - "tsx": "4.7.0", + "tsd": "0.30.7", + "tsx": "4.7.1", "typescript": "5.3.3", "wireit": "0.14.4" }, diff --git a/remote/test/puppeteer/packages/browsers/CHANGELOG.md b/remote/test/puppeteer/packages/browsers/CHANGELOG.md index abfb45bb6d..a2798068e9 100644 --- a/remote/test/puppeteer/packages/browsers/CHANGELOG.md +++ b/remote/test/puppeteer/packages/browsers/CHANGELOG.md @@ -1,5 +1,37 @@ # Changelog +## [2.1.0](https://github.com/puppeteer/puppeteer/compare/browsers-v2.0.1...browsers-v2.1.0) (2024-02-21) + + +### Features + +* allow comparing browser versions ([#11954](https://github.com/puppeteer/puppeteer/issues/11954)) ([bf71b34](https://github.com/puppeteer/puppeteer/commit/bf71b34fca73ed14eeb23616682799ff545fc371)) +* support local aliases when launching a browser ([#11947](https://github.com/puppeteer/puppeteer/issues/11947)) ([561e4cd](https://github.com/puppeteer/puppeteer/commit/561e4cd6ee79b19ac43f2c2fceaa1fce51052c02)) + + +### Bug Fixes + +* check if executable exists ([#11946](https://github.com/puppeteer/puppeteer/issues/11946)) ([e95a308](https://github.com/puppeteer/puppeteer/commit/e95a308c33021a80c9eb27a4ac02c607af60ff99)) +* implement a fallback to download URLs provided by dashboard ([#11951](https://github.com/puppeteer/puppeteer/issues/11951)) ([73c1f9b](https://github.com/puppeteer/puppeteer/commit/73c1f9bbf3c862decded533401e3bd26a18f8194)) + +## [2.0.1](https://github.com/puppeteer/puppeteer/compare/browsers-v2.0.0...browsers-v2.0.1) (2024-02-17) + + +### Bug Fixes + +* Chrome for Testing downloads have a new URL ([#11923](https://github.com/puppeteer/puppeteer/issues/11923)) ([f00a94a](https://github.com/puppeteer/puppeteer/commit/f00a94a809d38ee1c2c8cfc8597c66db9f3d243d)) + +## [2.0.0](https://github.com/puppeteer/puppeteer/compare/browsers-v1.9.1...browsers-v2.0.0) (2024-02-05) + + +### ⚠BREAKING CHANGES + +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) + +### Features + +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) ([953f420](https://github.com/puppeteer/puppeteer/commit/953f4207b17210fa7231225e6f29a826f77e0832)) + ## [1.9.1](https://github.com/puppeteer/puppeteer/compare/browsers-v1.9.0...browsers-v1.9.1) (2024-01-04) diff --git a/remote/test/puppeteer/packages/browsers/package.json b/remote/test/puppeteer/packages/browsers/package.json index 45de79abb8..0f2afa74de 100644 --- a/remote/test/puppeteer/packages/browsers/package.json +++ b/remote/test/puppeteer/packages/browsers/package.json @@ -1,12 +1,12 @@ { "name": "@puppeteer/browsers", - "version": "1.9.1", + "version": "2.1.0", "description": "Download and launch browsers", "scripts": { "build:docs": "wireit", "build": "wireit", "build:test": "wireit", - "clean": "../../tools/clean.js", + "clean": "../../tools/clean.mjs", "test": "wireit" }, "type": "commonjs", @@ -87,7 +87,7 @@ "author": "The Chromium Authors", "license": "Apache-2.0", "engines": { - "node": ">=16.3.0" + "node": ">=18" }, "files": [ "lib", @@ -98,10 +98,11 @@ "debug": "4.3.4", "extract-zip": "2.0.1", "progress": "2.0.3", - "proxy-agent": "6.3.1", - "tar-fs": "3.0.4", + "proxy-agent": "6.4.0", + "tar-fs": "3.0.5", "unbzip2-stream": "1.4.3", - "yargs": "17.7.2" + "yargs": "17.7.2", + "semver": "7.6.0" }, "devDependencies": { "@types/debug": "4.1.12", diff --git a/remote/test/puppeteer/packages/browsers/src/CLI.ts b/remote/test/puppeteer/packages/browsers/src/CLI.ts index 255f5545b4..281f22c9f5 100644 --- a/remote/test/puppeteer/packages/browsers/src/CLI.ts +++ b/remote/test/puppeteer/packages/browsers/src/CLI.ts @@ -173,6 +173,18 @@ export class CLI { 'Install the latest available build for the Chrome browser.' ); yargs.example( + '$0 install chrome@stable', + 'Install the latest available build for the Chrome browser from the stable channel.' + ); + yargs.example( + '$0 install chrome@beta', + 'Install the latest available build for the Chrome browser from the beta channel.' + ); + yargs.example( + '$0 install chrome@dev', + 'Install the latest available build for the Chrome browser from the dev channel.' + ); + yargs.example( '$0 install chrome@canary', 'Install the latest available build for the Chrome Canary browser.' ); @@ -238,6 +250,7 @@ export class CLI { } args.browser.buildId = pinnedVersion; } + const originalBuildId = args.browser.buildId; args.browser.buildId = await resolveBuildId( args.browser.name, args.platform, @@ -253,6 +266,10 @@ export class CLI { args.browser.buildId ), baseUrl: args.baseUrl, + buildIdAlias: + originalBuildId !== args.browser.buildId + ? originalBuildId + : undefined, }); console.log( `${args.browser.name}@${ diff --git a/remote/test/puppeteer/packages/browsers/src/Cache.ts b/remote/test/puppeteer/packages/browsers/src/Cache.ts index 13b465835a..e6b574d9dd 100644 --- a/remote/test/puppeteer/packages/browsers/src/Cache.ts +++ b/remote/test/puppeteer/packages/browsers/src/Cache.ts @@ -8,13 +8,18 @@ import fs from 'fs'; import os from 'os'; import path from 'path'; +import debug from 'debug'; + import { Browser, type BrowserPlatform, executablePathByBrowser, + getVersionComparator, } from './browser-data/browser-data.js'; import {detectBrowserPlatform} from './detectPlatform.js'; +const debugCache = debug('puppeteer:browsers:cache'); + /** * @public */ @@ -57,6 +62,14 @@ export class InstalledBrowser { this.buildId ); } + + readMetadata(): Metadata { + return this.#cache.readMetadata(this.browser); + } + + writeMetadata(metadata: Metadata): void { + this.#cache.writeMetadata(this.browser, metadata); + } } /** @@ -80,6 +93,11 @@ export interface ComputeExecutablePathOptions { buildId: string; } +export interface Metadata { + // Maps an alias (canary/latest/dev/etc.) to a buildId. + aliases: Record<string, string>; +} + /** * The cache used by Puppeteer relies on the following structure: * @@ -112,6 +130,39 @@ export class Cache { return path.join(this.#rootDir, browser); } + metadataFile(browser: Browser): string { + return path.join(this.browserRoot(browser), '.metadata'); + } + + readMetadata(browser: Browser): Metadata { + const metatadaPath = this.metadataFile(browser); + if (!fs.existsSync(metatadaPath)) { + return {aliases: {}}; + } + // TODO: add type-safe parsing. + const data = JSON.parse(fs.readFileSync(metatadaPath, 'utf8')); + if (typeof data !== 'object') { + throw new Error('.metadata is not an object'); + } + return data; + } + + writeMetadata(browser: Browser, metadata: Metadata): void { + const metatadaPath = this.metadataFile(browser); + fs.mkdirSync(path.dirname(metatadaPath), {recursive: true}); + fs.writeFileSync(metatadaPath, JSON.stringify(metadata, null, 2)); + } + + resolveAlias(browser: Browser, alias: string): string | undefined { + const metadata = this.readMetadata(browser); + if (alias === 'latest') { + return Object.values(metadata.aliases || {}) + .sort(getVersionComparator(browser)) + .at(-1); + } + return metadata.aliases[alias]; + } + installationDir( browser: Browser, platform: BrowserPlatform, @@ -134,6 +185,12 @@ export class Cache { platform: BrowserPlatform, buildId: string ): void { + const metadata = this.readMetadata(browser); + for (const alias of Object.keys(metadata.aliases)) { + if (metadata.aliases[alias] === buildId) { + delete metadata.aliases[alias]; + } + } fs.rmSync(this.installationDir(browser, platform, buildId), { force: true, recursive: true, @@ -180,6 +237,12 @@ export class Cache { `Cannot download a binary for the provided platform: ${os.platform()} (${os.arch()})` ); } + try { + options.buildId = + this.resolveAlias(options.browser, options.buildId) ?? options.buildId; + } catch { + debugCache('could not read .metadata file for the browser'); + } const installationDir = this.installationDir( options.browser, options.platform, diff --git a/remote/test/puppeteer/packages/browsers/src/browser-data/browser-data.ts b/remote/test/puppeteer/packages/browsers/src/browser-data/browser-data.ts index 67bb4990b2..3e78030aa7 100644 --- a/remote/test/puppeteer/packages/browsers/src/browser-data/browser-data.ts +++ b/remote/test/puppeteer/packages/browsers/src/browser-data/browser-data.ts @@ -43,6 +43,14 @@ export const executablePathByBrowser = { [Browser.FIREFOX]: firefox.relativeExecutablePath, }; +export const versionComparators = { + [Browser.CHROMEDRIVER]: chromedriver.compareVersions, + [Browser.CHROMEHEADLESSSHELL]: chromeHeadlessShell.compareVersions, + [Browser.CHROME]: chrome.compareVersions, + [Browser.CHROMIUM]: chromium.compareVersions, + [Browser.FIREFOX]: firefox.compareVersions, +}; + export {Browser, BrowserPlatform, ChromeReleaseChannel}; /** @@ -185,3 +193,15 @@ export function resolveSystemExecutablePath( return chrome.resolveSystemExecutablePath(platform, channel); } } + +/** + * Returns a version comparator for the given browser that can be used to sort + * browser versions. + * + * @public + */ +export function getVersionComparator( + browser: Browser +): (a: string, b: string) => number { + return versionComparators[browser]; +} diff --git a/remote/test/puppeteer/packages/browsers/src/browser-data/chrome-headless-shell.ts b/remote/test/puppeteer/packages/browsers/src/browser-data/chrome-headless-shell.ts index b1c6178de8..f5f65cdbd4 100644 --- a/remote/test/puppeteer/packages/browsers/src/browser-data/chrome-headless-shell.ts +++ b/remote/test/puppeteer/packages/browsers/src/browser-data/chrome-headless-shell.ts @@ -25,7 +25,7 @@ function folder(platform: BrowserPlatform): string { export function resolveDownloadUrl( platform: BrowserPlatform, buildId: string, - baseUrl = 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing' + baseUrl = 'https://storage.googleapis.com/chrome-for-testing-public' ): string { return `${baseUrl}/${resolveDownloadPath(platform, buildId).join('/')}`; } @@ -66,4 +66,4 @@ export function relativeExecutablePath( } } -export {resolveBuildId} from './chrome.js'; +export {resolveBuildId, compareVersions} from './chrome.js'; diff --git a/remote/test/puppeteer/packages/browsers/src/browser-data/chrome.ts b/remote/test/puppeteer/packages/browsers/src/browser-data/chrome.ts index c6329255c3..c7975163fc 100644 --- a/remote/test/puppeteer/packages/browsers/src/browser-data/chrome.ts +++ b/remote/test/puppeteer/packages/browsers/src/browser-data/chrome.ts @@ -6,6 +6,8 @@ import path from 'path'; +import semver from 'semver'; + import {getJSON} from '../httpUtil.js'; import {BrowserPlatform, ChromeReleaseChannel} from './types.js'; @@ -28,7 +30,7 @@ function folder(platform: BrowserPlatform): string { export function resolveDownloadUrl( platform: BrowserPlatform, buildId: string, - baseUrl = 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing' + baseUrl = 'https://storage.googleapis.com/chrome-for-testing-public' ): string { return `${baseUrl}/${resolveDownloadPath(platform, buildId).join('/')}`; } @@ -193,3 +195,19 @@ export function resolveSystemExecutablePath( `Unable to detect browser executable path for '${channel}' on ${platform}.` ); } + +export function compareVersions(a: string, b: string): number { + if (!semver.valid(a)) { + throw new Error(`Version ${a} is not a valid semver version`); + } + if (!semver.valid(b)) { + throw new Error(`Version ${b} is not a valid semver version`); + } + if (semver.gt(a, b)) { + return 1; + } else if (semver.lt(a, b)) { + return -1; + } else { + return 0; + } +} diff --git a/remote/test/puppeteer/packages/browsers/src/browser-data/chromedriver.ts b/remote/test/puppeteer/packages/browsers/src/browser-data/chromedriver.ts index 290598d0d7..2f1242b249 100644 --- a/remote/test/puppeteer/packages/browsers/src/browser-data/chromedriver.ts +++ b/remote/test/puppeteer/packages/browsers/src/browser-data/chromedriver.ts @@ -25,7 +25,7 @@ function folder(platform: BrowserPlatform): string { export function resolveDownloadUrl( platform: BrowserPlatform, buildId: string, - baseUrl = 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing' + baseUrl = 'https://storage.googleapis.com/chrome-for-testing-public' ): string { return `${baseUrl}/${resolveDownloadPath(platform, buildId).join('/')}`; } @@ -53,4 +53,4 @@ export function relativeExecutablePath( } } -export {resolveBuildId} from './chrome.js'; +export {resolveBuildId, compareVersions} from './chrome.js'; diff --git a/remote/test/puppeteer/packages/browsers/src/browser-data/chromium.ts b/remote/test/puppeteer/packages/browsers/src/browser-data/chromium.ts index 09cfc987a8..820e76d018 100644 --- a/remote/test/puppeteer/packages/browsers/src/browser-data/chromium.ts +++ b/remote/test/puppeteer/packages/browsers/src/browser-data/chromium.ts @@ -86,3 +86,7 @@ export async function resolveBuildId( ) ); } + +export function compareVersions(a: string, b: string): number { + return Number(a) - Number(b); +} diff --git a/remote/test/puppeteer/packages/browsers/src/browser-data/firefox.ts b/remote/test/puppeteer/packages/browsers/src/browser-data/firefox.ts index ccc30fa1b5..87e3804c8f 100644 --- a/remote/test/puppeteer/packages/browsers/src/browser-data/firefox.ts +++ b/remote/test/puppeteer/packages/browsers/src/browser-data/firefox.ts @@ -235,10 +235,6 @@ function defaultProfilePreferences( // Disable the GFX sanity window 'media.sanity-test.disabled': true, - // Prevent various error message on the console - // jest-puppeteer asserts that no error message is emitted by the console - 'network.cookie.cookieBehavior': 0, - // Disable experimental feature that is only available in Nightly 'network.cookie.sameSite.laxByDefault': false, @@ -328,3 +324,8 @@ async function writePreferences(options: ProfileOptions): Promise<void> { await fs.promises.copyFile(prefsPath, prefsBackupPath); } } + +export function compareVersions(a: string, b: string): number { + // TODO: this is a not very reliable check. + return parseInt(a.replace('.', ''), 16) - parseInt(b.replace('.', ''), 16); +} diff --git a/remote/test/puppeteer/packages/browsers/src/install.ts b/remote/test/puppeteer/packages/browsers/src/install.ts index 375c75babc..e78b2c3461 100644 --- a/remote/test/puppeteer/packages/browsers/src/install.ts +++ b/remote/test/puppeteer/packages/browsers/src/install.ts @@ -11,15 +11,15 @@ import os from 'os'; import path from 'path'; import { - type Browser, - type BrowserPlatform, + Browser, + BrowserPlatform, downloadUrls, } from './browser-data/browser-data.js'; import {Cache, InstalledBrowser} from './Cache.js'; import {debug} from './debug.js'; import {detectBrowserPlatform} from './detectPlatform.js'; import {unpackArchive} from './fileUtil.js'; -import {downloadFile, headHttpRequest} from './httpUtil.js'; +import {downloadFile, getJSON, headHttpRequest} from './httpUtil.js'; const debugInstall = debug('puppeteer:browsers:install'); @@ -63,6 +63,13 @@ export interface InstallOptions { */ buildId: string; /** + * An alias for the provided `buildId`. It will be used to maintain local + * metadata to support aliases in the `launch` command. + * + * @example 'canary' + */ + buildIdAlias?: string; + /** * Provides information about the progress of the download. */ downloadProgressCallback?: ( @@ -74,7 +81,7 @@ export interface InstallOptions { * * @defaultValue Either * - * - https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing or + * - https://storage.googleapis.com/chrome-for-testing-public or * - https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central * */ @@ -115,6 +122,68 @@ export async function install( options.buildId, options.baseUrl ); + try { + return await installUrl(url, options); + } catch (err) { + debugInstall(`Error downloading from ${url}.`); + switch (options.browser) { + case Browser.CHROME: + case Browser.CHROMEDRIVER: + case Browser.CHROMEHEADLESSSHELL: { + debugInstall( + `Trying to find download URL via https://googlechromelabs.github.io/chrome-for-testing.` + ); + interface Version { + downloads: Record<string, Array<{platform: string; url: string}>>; + } + const version = (await getJSON( + new URL( + `https://googlechromelabs.github.io/chrome-for-testing/${options.buildId}.json` + ) + )) as Version; + let platform = ''; + switch (options.platform) { + case BrowserPlatform.LINUX: + platform = 'linux64'; + break; + case BrowserPlatform.MAC_ARM: + platform = 'mac-arm64'; + break; + case BrowserPlatform.MAC: + platform = 'mac-x64'; + break; + case BrowserPlatform.WIN32: + platform = 'win32'; + break; + case BrowserPlatform.WIN64: + platform = 'win64'; + break; + } + const url = version.downloads[options.browser]?.find(link => { + return link['platform'] === platform; + })?.url; + if (url) { + debugInstall(`Falling back to downloading from ${url}.`); + return await installUrl(new URL(url), options); + } + throw err; + } + default: + throw err; + } + } +} + +async function installUrl( + url: URL, + options: InstallOptions +): Promise<InstalledBrowser | string> { + options.platform ??= detectBrowserPlatform(); + if (!options.platform) { + throw new Error( + `Cannot download a binary for the provided platform: ${os.platform()} (${os.arch()})` + ); + } const fileName = url.toString().split('/').pop(); assert(fileName, `A malformed download URL was found: ${url}.`); const cache = new Cache(options.cacheDir); @@ -140,15 +209,22 @@ export async function install( options.platform, options.buildId ); - if (existsSync(outputPath)) { - return new InstalledBrowser( - cache, - options.browser, - options.buildId, - options.platform - ); - } + try { + if (existsSync(outputPath)) { + const installedBrowser = new InstalledBrowser( + cache, + options.browser, + options.buildId, + options.platform + ); + if (!existsSync(installedBrowser.executablePath)) { + throw new Error( + `The browser folder (${outputPath}) exists but the executable (${installedBrowser.executablePath}) is missing` + ); + } + return installedBrowser; + } debugInstall(`Downloading binary from ${url}`); try { debugTime('download'); @@ -164,17 +240,23 @@ export async function install( } finally { debugTimeEnd('extract'); } + const installedBrowser = new InstalledBrowser( + cache, + options.browser, + options.buildId, + options.platform + ); + if (options.buildIdAlias) { + const metadata = installedBrowser.readMetadata(); + metadata.aliases[options.buildIdAlias] = options.buildId; + installedBrowser.writeMetadata(metadata); + } + return installedBrowser; } finally { if (existsSync(archivePath)) { await unlink(archivePath); } } - return new InstalledBrowser( - cache, - options.browser, - options.buildId, - options.platform - ); } /** diff --git a/remote/test/puppeteer/packages/browsers/src/main.ts b/remote/test/puppeteer/packages/browsers/src/main.ts index df93de530d..c03c0c0090 100644 --- a/remote/test/puppeteer/packages/browsers/src/main.ts +++ b/remote/test/puppeteer/packages/browsers/src/main.ts @@ -37,6 +37,7 @@ export { BrowserPlatform, ChromeReleaseChannel, createProfile, + getVersionComparator, } from './browser-data/browser-data.js'; export {CLI, makeProgressCallback} from './CLI.js'; export {Cache, InstalledBrowser} from './Cache.js'; diff --git a/remote/test/puppeteer/packages/browsers/test/src/Cache.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/Cache.spec.ts new file mode 100644 index 0000000000..e8a3fb9619 --- /dev/null +++ b/remote/test/puppeteer/packages/browsers/test/src/Cache.spec.ts @@ -0,0 +1,72 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import assert from 'assert'; +import fs from 'fs'; +import os from 'os'; +import path from 'path'; + +import {Browser, Cache} from '../../lib/cjs/main.js'; + +describe('Cache', () => { + let tmpDir = '/tmp/puppeteer-browsers-test'; + let cache: Cache; + + beforeEach(() => { + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'puppeteer-browsers-test')); + cache = new Cache(tmpDir); + }); + + afterEach(() => { + cache.clear(); + }); + + it('return empty metadata if .metadata file does not exist', async function () { + assert.deepStrictEqual(cache.readMetadata(Browser.CHROME), { + aliases: {}, + }); + }); + + it('throw an error if .metadata is malformed', async function () { + // @ts-expect-error wrong type on purpose; + cache.writeMetadata(Browser.CHROME, 'metadata'); + assert.throws(() => { + return cache.readMetadata(Browser.CHROME); + }, new Error(`.metadata is not an object`)); + }); + + it('writes and reads .metadata', async function () { + cache.writeMetadata(Browser.CHROME, { + aliases: { + canary: '123.0.0.0', + }, + }); + assert.deepStrictEqual(cache.readMetadata(Browser.CHROME), { + aliases: { + canary: '123.0.0.0', + }, + }); + + assert.deepStrictEqual( + cache.resolveAlias(Browser.CHROME, 'canary'), + '123.0.0.0' + ); + }); + + it('resolves latest', async function () { + cache.writeMetadata(Browser.CHROME, { + aliases: { + canary: '115.0.5789', + stable: '114.0.5789', + }, + }); + + assert.deepStrictEqual( + cache.resolveAlias(Browser.CHROME, 'latest'), + '115.0.5789' + ); + }); +}); diff --git a/remote/test/puppeteer/packages/browsers/test/src/chrome-headless-shell/chrome-headless-shell-data.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/chrome-headless-shell/chrome-headless-shell-data.spec.ts index 65008b5edb..2a9f03e2cc 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/chrome-headless-shell/chrome-headless-shell-data.spec.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/chrome-headless-shell/chrome-headless-shell-data.spec.ts @@ -18,23 +18,23 @@ describe('chrome-headless-shell', () => { it('should resolve download URLs', () => { assert.strictEqual( resolveDownloadUrl(BrowserPlatform.LINUX, '118.0.5950.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/linux64/chrome-headless-shell-linux64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/118.0.5950.0/linux64/chrome-headless-shell-linux64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.MAC, '118.0.5950.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/mac-x64/chrome-headless-shell-mac-x64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/118.0.5950.0/mac-x64/chrome-headless-shell-mac-x64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.MAC_ARM, '118.0.5950.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/mac-arm64/chrome-headless-shell-mac-arm64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/118.0.5950.0/mac-arm64/chrome-headless-shell-mac-arm64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.WIN32, '118.0.5950.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/win32/chrome-headless-shell-win32.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/118.0.5950.0/win32/chrome-headless-shell-win32.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.WIN64, '118.0.5950.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/win64/chrome-headless-shell-win64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/118.0.5950.0/win64/chrome-headless-shell-win64.zip' ); }); diff --git a/remote/test/puppeteer/packages/browsers/test/src/chrome/chrome-data.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/chrome/chrome-data.spec.ts index 510afa8454..4d5bc980b1 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/chrome/chrome-data.spec.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/chrome/chrome-data.spec.ts @@ -16,29 +16,30 @@ import { relativeExecutablePath, resolveSystemExecutablePath, resolveBuildId, + compareVersions, } from '../../../lib/cjs/browser-data/chrome.js'; describe('Chrome', () => { it('should resolve download URLs', () => { assert.strictEqual( resolveDownloadUrl(BrowserPlatform.LINUX, '113.0.5672.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/113.0.5672.0/linux64/chrome-linux64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/linux64/chrome-linux64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.MAC, '113.0.5672.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/113.0.5672.0/mac-x64/chrome-mac-x64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/mac-x64/chrome-mac-x64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.MAC_ARM, '113.0.5672.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/113.0.5672.0/mac-arm64/chrome-mac-arm64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/mac-arm64/chrome-mac-arm64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.WIN32, '113.0.5672.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/113.0.5672.0/win32/chrome-win32.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/win32/chrome-win32.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.WIN64, '113.0.5672.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/113.0.5672.0/win64/chrome-win64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/win64/chrome-win64.zip' ); }); @@ -116,4 +117,10 @@ describe('Chrome', () => { it('should resolve build prefix', async () => { assert.strictEqual(await resolveBuildId('115.0.5790'), '115.0.5790.170'); }); + + it('should compare versions', async () => { + assert.ok(compareVersions('115.0.5790', '115.0.5789') >= 1); + assert.ok(compareVersions('115.0.5789', '115.0.5790') <= -1); + assert.ok(compareVersions('115.0.5790', '115.0.5790') === 0); + }); }); diff --git a/remote/test/puppeteer/packages/browsers/test/src/chrome/install.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/chrome/install.spec.ts index 8103ff3612..f669d1c57c 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/chrome/install.spec.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/chrome/install.spec.ts @@ -17,6 +17,7 @@ import { Browser, BrowserPlatform, Cache, + computeExecutablePath, } from '../../../lib/cjs/main.js'; import {getServerUrl, setupTestServer} from '../utils.js'; import {testChromeBuildId} from '../versions.js'; @@ -63,6 +64,42 @@ describe('Chrome install', () => { ); }); + it('can detect missing executables', async function () { + this.timeout(60000); + const expectedOutputPath = path.join( + tmpDir, + 'chrome', + `${BrowserPlatform.LINUX}-${testChromeBuildId}` + ); + fs.mkdirSync(expectedOutputPath, {recursive: true}); + assert.strictEqual(fs.existsSync(expectedOutputPath), true); + async function installThatThrows(): Promise<Error | undefined> { + try { + await install({ + cacheDir: tmpDir, + browser: Browser.CHROME, + platform: BrowserPlatform.LINUX, + buildId: testChromeBuildId, + }); + return undefined; + } catch (err) { + return err as Error; + } + } + assert.strictEqual( + (await installThatThrows())?.message, + `The browser folder (${expectedOutputPath}) exists but the executable (${computeExecutablePath( + { + cacheDir: tmpDir, + browser: Browser.CHROME, + platform: BrowserPlatform.LINUX, + buildId: testChromeBuildId, + } + )}) is missing` + ); + assert.strictEqual(fs.existsSync(expectedOutputPath), true); + }); + it('should download a buildId that is a zip archive', async function () { this.timeout(60000); const expectedOutputPath = path.join( @@ -100,30 +137,21 @@ describe('Chrome install', () => { ); }); - it('throws on invalid URL', async function () { + it('falls back to the chrome-for-testing dashboard URLs if URL is not available', async function () { const expectedOutputPath = path.join( tmpDir, 'chrome', `${BrowserPlatform.LINUX}-${testChromeBuildId}` ); assert.strictEqual(fs.existsSync(expectedOutputPath), false); - - async function installThatThrows(): Promise<unknown> { - try { - await install({ - cacheDir: tmpDir, - browser: Browser.CHROME, - platform: BrowserPlatform.LINUX, - buildId: testChromeBuildId, - baseUrl: 'https://127.0.0.1', - }); - return undefined; - } catch (err) { - return err; - } - } - assert.ok(await installThatThrows()); - assert.strictEqual(fs.existsSync(expectedOutputPath), false); + await install({ + cacheDir: tmpDir, + browser: Browser.CHROME, + platform: BrowserPlatform.LINUX, + buildId: testChromeBuildId, + baseUrl: 'https://127.0.0.1', + }); + assert.strictEqual(fs.existsSync(expectedOutputPath), true); }); describe('with proxy', () => { @@ -198,7 +226,7 @@ describe('Chrome install', () => { true ); assert.deepStrictEqual(proxiedRequestUrls, [ - getServerUrl() + '/113.0.5672.0/linux64/chrome-linux64.zip', + getServerUrl() + `/${testChromeBuildId}/linux64/chrome-linux64.zip`, ]); assert.deepStrictEqual(proxiedRequestHosts, [ getServerUrl().replace('http://', ''), @@ -223,7 +251,7 @@ describe('Chrome install', () => { assert.strictEqual(browser.path, expectedOutputPath); assert.ok(fs.existsSync(expectedOutputPath)); assert.deepStrictEqual(proxiedRequestUrls, [ - getServerUrl() + '/113.0.5672.0/linux64/chrome-linux64.zip', + getServerUrl() + `/${testChromeBuildId}/linux64/chrome-linux64.zip`, ]); assert.deepStrictEqual(proxiedRequestHosts, [ getServerUrl().replace('http://', ''), diff --git a/remote/test/puppeteer/packages/browsers/test/src/chromedriver/chromedriver-data.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/chromedriver/chromedriver-data.spec.ts index 62522d88f4..8a9d07f667 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/chromedriver/chromedriver-data.spec.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/chromedriver/chromedriver-data.spec.ts @@ -18,23 +18,23 @@ describe('ChromeDriver', () => { it('should resolve download URLs', () => { assert.strictEqual( resolveDownloadUrl(BrowserPlatform.LINUX, '115.0.5763.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5763.0/linux64/chromedriver-linux64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/115.0.5763.0/linux64/chromedriver-linux64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.MAC, '115.0.5763.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5763.0/mac-x64/chromedriver-mac-x64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/115.0.5763.0/mac-x64/chromedriver-mac-x64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.MAC_ARM, '115.0.5763.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5763.0/mac-arm64/chromedriver-mac-arm64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/115.0.5763.0/mac-arm64/chromedriver-mac-arm64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.WIN32, '115.0.5763.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5763.0/win32/chromedriver-win32.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/115.0.5763.0/win32/chromedriver-win32.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.WIN64, '115.0.5763.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5763.0/win64/chromedriver-win64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/115.0.5763.0/win64/chromedriver-win64.zip' ); }); diff --git a/remote/test/puppeteer/packages/browsers/test/src/chromium/chromium-data.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/chromium/chromium-data.spec.ts index 601efccc47..ecb7946c99 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/chromium/chromium-data.spec.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/chromium/chromium-data.spec.ts @@ -11,6 +11,7 @@ import {BrowserPlatform} from '../../../lib/cjs/browser-data/browser-data.js'; import { resolveDownloadUrl, relativeExecutablePath, + compareVersions, } from '../../../lib/cjs/browser-data/chromium.js'; describe('Chromium', () => { @@ -59,4 +60,10 @@ describe('Chromium', () => { path.join('chrome-win', 'chrome.exe') ); }); + + it('should compare versions', async () => { + assert.ok(compareVersions('12372323', '12372322') >= 1); + assert.ok(compareVersions('12372322', '12372323') <= -1); + assert.ok(compareVersions('12372323', '12372323') === 0); + }); }); diff --git a/remote/test/puppeteer/packages/browsers/test/src/firefox/firefox-data.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/firefox/firefox-data.spec.ts index d0bb056090..b5dd2db0b3 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/firefox/firefox-data.spec.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/firefox/firefox-data.spec.ts @@ -11,6 +11,7 @@ import path from 'path'; import {BrowserPlatform} from '../../../lib/cjs/browser-data/browser-data.js'; import { + compareVersions, createProfile, relativeExecutablePath, resolveDownloadUrl, @@ -94,4 +95,10 @@ describe('Firefox', () => { assert.ok(text.includes(`user_pref("test", 1);`)); // custom preference. }); }); + + it('should compare versions', async () => { + assert.ok(compareVersions('111.0a1', '110.0a1') >= 1); + assert.ok(compareVersions('110.0a1', '111.0a1') <= -1); + assert.ok(compareVersions('111.0a1', '111.0a1') === 0); + }); }); diff --git a/remote/test/puppeteer/packages/browsers/test/src/firefox/install.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/firefox/install.spec.ts index 1bada43729..29bc76d1b2 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/firefox/install.spec.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/firefox/install.spec.ts @@ -49,6 +49,32 @@ describe('Firefox install', () => { assert.ok(fs.existsSync(expectedOutputPath)); }); + it('throws on invalid URL', async function () { + const expectedOutputPath = path.join( + tmpDir, + 'chrome', + `${BrowserPlatform.LINUX}-${testFirefoxBuildId}` + ); + assert.strictEqual(fs.existsSync(expectedOutputPath), false); + + async function installThatThrows(): Promise<unknown> { + try { + await install({ + cacheDir: tmpDir, + browser: Browser.FIREFOX, + platform: BrowserPlatform.LINUX, + buildId: testFirefoxBuildId, + baseUrl: 'https://127.0.0.1', + }); + return undefined; + } catch (err) { + return err; + } + } + assert.ok(await installThatThrows()); + assert.strictEqual(fs.existsSync(expectedOutputPath), false); + }); + // install relies on the `hdiutil` utility on MacOS. // The utility is not available on other platforms. (os.platform() === 'darwin' ? it : it.skip)( diff --git a/remote/test/puppeteer/packages/browsers/test/src/mocha-utils.ts b/remote/test/puppeteer/packages/browsers/test/src/mocha-utils.ts index 245a0048b2..f3ee678d4e 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/mocha-utils.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/mocha-utils.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import debug from 'debug'; export const mochaHooks = { diff --git a/remote/test/puppeteer/packages/browsers/test/src/tsconfig.json b/remote/test/puppeteer/packages/browsers/test/src/tsconfig.json index 03eae4a458..097d55c06e 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/tsconfig.json +++ b/remote/test/puppeteer/packages/browsers/test/src/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "module": "NodeNext", "moduleResolution": "NodeNext", - "outDir": "../build", + "outDir": "../build" }, - "references": [{"path": "../../tsconfig.json"}], + "references": [{"path": "../../tsconfig.json"}] } diff --git a/remote/test/puppeteer/packages/browsers/test/src/versions.ts b/remote/test/puppeteer/packages/browsers/test/src/versions.ts index 3e13b8fc61..83f26ca41a 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/versions.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/versions.ts @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -export const testChromeBuildId = '113.0.5672.0'; +export const testChromeBuildId = '121.0.6167.85'; export const testChromiumBuildId = '1083080'; -export const testFirefoxBuildId = '123.0a1'; -export const testChromeDriverBuildId = '115.0.5763.0'; -export const testChromeHeadlessShellBuildId = '118.0.5950.0'; +export const testFirefoxBuildId = '125.0a1'; +export const testChromeDriverBuildId = '121.0.6167.85'; +export const testChromeHeadlessShellBuildId = '121.0.6167.85'; diff --git a/remote/test/puppeteer/packages/browsers/tools/updateVersions.mjs b/remote/test/puppeteer/packages/browsers/tools/updateVersions.mjs index 9fb704baf5..4129428986 100644 --- a/remote/test/puppeteer/packages/browsers/tools/updateVersions.mjs +++ b/remote/test/puppeteer/packages/browsers/tools/updateVersions.mjs @@ -5,12 +5,15 @@ */ import fs from 'node:fs/promises'; +import path from 'path'; +import url from 'url'; import actions from '@actions/core'; import {testFirefoxBuildId} from '../test/build/versions.js'; -const filePath = './test/src/versions.ts'; +const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); +const filePath = path.join(__dirname, '../test/src/versions.ts'); const getVersion = async () => { // https://stackoverflow.com/a/1732454/96656 diff --git a/remote/test/puppeteer/packages/browsers/tsconfig.json b/remote/test/puppeteer/packages/browsers/tsconfig.json index b662532a01..a219f8b704 100644 --- a/remote/test/puppeteer/packages/browsers/tsconfig.json +++ b/remote/test/puppeteer/packages/browsers/tsconfig.json @@ -3,6 +3,6 @@ "files": [], "references": [ {"path": "src/tsconfig.esm.json"}, - {"path": "src/tsconfig.cjs.json"}, - ], + {"path": "src/tsconfig.cjs.json"} + ] } diff --git a/remote/test/puppeteer/packages/ng-schematics/CHANGELOG.md b/remote/test/puppeteer/packages/ng-schematics/CHANGELOG.md index a483c4f2fb..fbe3408b45 100644 --- a/remote/test/puppeteer/packages/ng-schematics/CHANGELOG.md +++ b/remote/test/puppeteer/packages/ng-schematics/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [0.6.0](https://github.com/puppeteer/puppeteer/compare/ng-schematics-v0.5.6...ng-schematics-v0.6.0) (2024-02-05) + + +### ⚠BREAKING CHANGES + +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) + +### Features + +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) ([953f420](https://github.com/puppeteer/puppeteer/commit/953f4207b17210fa7231225e6f29a826f77e0832)) + ## [0.5.6](https://github.com/puppeteer/puppeteer/compare/ng-schematics-v0.5.5...ng-schematics-v0.5.6) (2024-01-16) diff --git a/remote/test/puppeteer/packages/ng-schematics/package.json b/remote/test/puppeteer/packages/ng-schematics/package.json index 29db1dcdc9..6d88d23926 100644 --- a/remote/test/puppeteer/packages/ng-schematics/package.json +++ b/remote/test/puppeteer/packages/ng-schematics/package.json @@ -1,10 +1,10 @@ { "name": "@puppeteer/ng-schematics", - "version": "0.5.6", + "version": "0.6.0", "description": "Puppeteer Angular schematics", "scripts": { "build": "wireit", - "clean": "../../tools/clean.js", + "clean": "../../tools/clean.mjs", "dev:test": "npm run test --watch", "dev": "npm run build --watch", "unit": "wireit" @@ -48,16 +48,16 @@ "author": "The Chromium Authors", "license": "Apache-2.0", "engines": { - "node": ">=16.13.2" + "node": ">=18" }, "dependencies": { - "@angular-devkit/architect": "^0.1701.1", - "@angular-devkit/core": "^17.0.7", - "@angular-devkit/schematics": "^17.0.7" + "@angular-devkit/architect": "0.1702.2", + "@angular-devkit/core": "17.2.2", + "@angular-devkit/schematics": "17.2.2" }, "devDependencies": { - "@schematics/angular": "^17.0.7", - "@angular/cli": "^17.0.7" + "@schematics/angular": "17.2.2", + "@angular/cli": "17.2.2" }, "files": [ "lib", diff --git a/remote/test/puppeteer/packages/ng-schematics/src/builders/puppeteer/index.ts b/remote/test/puppeteer/packages/ng-schematics/src/builders/puppeteer/index.ts index 82a1e8e7da..e8caab83c9 100644 --- a/remote/test/puppeteer/packages/ng-schematics/src/builders/puppeteer/index.ts +++ b/remote/test/puppeteer/packages/ng-schematics/src/builders/puppeteer/index.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {spawn} from 'child_process'; import {normalize, join} from 'path'; diff --git a/remote/test/puppeteer/packages/ng-schematics/src/schematics/ng-add/files/common/e2e/tests/utils.ts.template b/remote/test/puppeteer/packages/ng-schematics/src/schematics/ng-add/files/common/e2e/tests/utils.ts.template index 2136f99a3a..1e291839fe 100644 --- a/remote/test/puppeteer/packages/ng-schematics/src/schematics/ng-add/files/common/e2e/tests/utils.ts.template +++ b/remote/test/puppeteer/packages/ng-schematics/src/schematics/ng-add/files/common/e2e/tests/utils.ts.template @@ -10,15 +10,11 @@ let page: puppeteer.Page; export function setupBrowserHooks(path = ''): void { <% if(testRunner == 'jasmine' || testRunner == 'jest') { %> beforeAll(async () => { - browser = await puppeteer.launch({ - headless: 'new' - }); + browser = await puppeteer.launch(); }); <% } %><% if(testRunner == 'mocha' || testRunner == 'node') { %> before(async () => { - browser = await puppeteer.launch({ - headless: 'new' - }); + browser = await puppeteer.launch(); }); <% } %> diff --git a/remote/test/puppeteer/packages/ng-schematics/test/src/config.test.ts b/remote/test/puppeteer/packages/ng-schematics/test/src/config.test.ts index e4ec03ed54..9390e6fd74 100644 --- a/remote/test/puppeteer/packages/ng-schematics/test/src/config.test.ts +++ b/remote/test/puppeteer/packages/ng-schematics/test/src/config.test.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {describe, it} from 'node:test'; import expect from 'expect'; diff --git a/remote/test/puppeteer/packages/ng-schematics/test/src/e2e.test.ts b/remote/test/puppeteer/packages/ng-schematics/test/src/e2e.test.ts index 8ae211cd59..2d80c613f9 100644 --- a/remote/test/puppeteer/packages/ng-schematics/test/src/e2e.test.ts +++ b/remote/test/puppeteer/packages/ng-schematics/test/src/e2e.test.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {describe, it} from 'node:test'; import expect from 'expect'; diff --git a/remote/test/puppeteer/packages/ng-schematics/test/src/ng-add.test.ts b/remote/test/puppeteer/packages/ng-schematics/test/src/ng-add.test.ts index d912c5dc3d..56f82ef926 100644 --- a/remote/test/puppeteer/packages/ng-schematics/test/src/ng-add.test.ts +++ b/remote/test/puppeteer/packages/ng-schematics/test/src/ng-add.test.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {describe, it} from 'node:test'; import expect from 'expect'; diff --git a/remote/test/puppeteer/packages/ng-schematics/test/src/utils.ts b/remote/test/puppeteer/packages/ng-schematics/test/src/utils.ts index 503cbd5cec..ea74d8e21f 100644 --- a/remote/test/puppeteer/packages/ng-schematics/test/src/utils.ts +++ b/remote/test/puppeteer/packages/ng-schematics/test/src/utils.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import https from 'https'; import {before, after} from 'node:test'; import {join} from 'path'; diff --git a/remote/test/puppeteer/packages/ng-schematics/test/tsconfig.json b/remote/test/puppeteer/packages/ng-schematics/test/tsconfig.json index 3d45f9cc54..8d9f78e0f6 100644 --- a/remote/test/puppeteer/packages/ng-schematics/test/tsconfig.json +++ b/remote/test/puppeteer/packages/ng-schematics/test/tsconfig.json @@ -3,8 +3,8 @@ "compilerOptions": { "rootDir": "src/", "outDir": "build/", - "types": ["node"], + "types": ["node"] }, "include": ["src/**/*"], - "references": [{"path": "../tsconfig.json"}], + "references": [{"path": "../tsconfig.json"}] } diff --git a/remote/test/puppeteer/packages/ng-schematics/test/tsdoc.json b/remote/test/puppeteer/packages/ng-schematics/test/tsdoc.json new file mode 100644 index 0000000000..f5b91f4af6 --- /dev/null +++ b/remote/test/puppeteer/packages/ng-schematics/test/tsdoc.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + + "extends": ["@microsoft/api-extractor/extends/tsdoc-base.json"], + "tagDefinitions": [ + { + "tagName": "@license", + "syntaxKind": "modifier", + "allowMultiple": false + } + ], + "supportForTags": { + "@license": true + } +} diff --git a/remote/test/puppeteer/packages/ng-schematics/tools/projects.mjs b/remote/test/puppeteer/packages/ng-schematics/tools/projects.mjs index 985200881e..1c6e346a6a 100644 --- a/remote/test/puppeteer/packages/ng-schematics/tools/projects.mjs +++ b/remote/test/puppeteer/packages/ng-schematics/tools/projects.mjs @@ -13,8 +13,14 @@ import {cwd} from 'process'; class AngularProject { static ports = new Set(); static randomPort() { - const min = 4000; - const max = 9876; + /** + * Some ports are restricted by Chromium and will fail to connect + * to prevent we start after the + * + * https://source.chromium.org/chromium/chromium/src/+/main:net/base/port_util.cc;l=107?q=kRestrictedPorts&ss=chromium + */ + const min = 10101; + const max = 20202; return Math.floor(Math.random() * (max - min + 1) + min); } static port() { diff --git a/remote/test/puppeteer/packages/ng-schematics/tsconfig.json b/remote/test/puppeteer/packages/ng-schematics/tsconfig.json index 40529c7d17..16b55d5233 100644 --- a/remote/test/puppeteer/packages/ng-schematics/tsconfig.json +++ b/remote/test/puppeteer/packages/ng-schematics/tsconfig.json @@ -10,8 +10,8 @@ "skipDefaultLibCheck": true, "skipLibCheck": true, "sourceMap": true, - "types": ["node"], + "types": ["node"] }, "include": ["src/**/*"], - "exclude": ["src/**/files/**/*"], + "exclude": ["src/**/files/**/*"] } diff --git a/remote/test/puppeteer/packages/puppeteer-core/.gitignore b/remote/test/puppeteer/packages/puppeteer-core/.gitignore index 42061c01a1..3d32a7ba82 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/.gitignore +++ b/remote/test/puppeteer/packages/puppeteer-core/.gitignore @@ -1 +1 @@ -README.md
\ No newline at end of file +/README.md
\ No newline at end of file diff --git a/remote/test/puppeteer/packages/puppeteer-core/CHANGELOG.md b/remote/test/puppeteer/packages/puppeteer-core/CHANGELOG.md index 341d706fb4..5076077c9f 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/CHANGELOG.md +++ b/remote/test/puppeteer/packages/puppeteer-core/CHANGELOG.md @@ -20,6 +20,146 @@ All notable changes to this project will be documented in this file. See [standa * dependencies * @puppeteer/browsers bumped from 1.5.1 to 1.6.0 +## [22.4.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-core-v22.3.0...puppeteer-core-v22.4.0) (2024-03-05) + + +### Features + +* implement ElementHandle.uploadFile for WebDriver BiDi ([#11963](https://github.com/puppeteer/puppeteer/issues/11963)) ([accf2b6](https://github.com/puppeteer/puppeteer/commit/accf2b6ca84c93bc700277b4e3382d894fb45a76)) +* **webdriver:** support `Page.deleteCookie()` for WebDriver BiDi ([#12031](https://github.com/puppeteer/puppeteer/issues/12031)) ([7fe22b5](https://github.com/puppeteer/puppeteer/commit/7fe22b533dc96104f28696eb4ff96b2543fd8e5b)) + + +### Bug Fixes + +* roll to Chrome 122.0.6261.94 (r1250580) ([#12012](https://github.com/puppeteer/puppeteer/issues/12012)) ([7ba5529](https://github.com/puppeteer/puppeteer/commit/7ba5529f8d6f8ed085968b7a9bc6f25f8d91abd5)) +* **webdriver:** wait for response if the response has not completed once navigation has finished ([#12018](https://github.com/puppeteer/puppeteer/issues/12018)) ([6d8831a](https://github.com/puppeteer/puppeteer/commit/6d8831a9c398230f2543c3862d3fe5fc7cd2b940)) + +## [22.3.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-core-v22.2.0...puppeteer-core-v22.3.0) (2024-02-25) + + +### Features + +* implement permissions for WebDriver BiDi ([#11979](https://github.com/puppeteer/puppeteer/issues/11979)) ([3a467c3](https://github.com/puppeteer/puppeteer/commit/3a467c39cb60de4237081ee201bd86051887c2f2)) + + +### Bug Fixes + +* roll to Chrome 122.0.6261.69 (r1250580) ([#11991](https://github.com/puppeteer/puppeteer/issues/11991)) ([eb2c334](https://github.com/puppeteer/puppeteer/commit/eb2c33485ec473e085c6b76b45554758764349d6)) +* supress viewport errors for pages that do not support changing it ([#11970](https://github.com/puppeteer/puppeteer/issues/11970)) ([753a954](https://github.com/puppeteer/puppeteer/commit/753a954456699fc06adf67837225f306711af856)) + +## [22.2.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-core-v22.1.0...puppeteer-core-v22.2.0) (2024-02-21) + + +### Features + +* roll to Chrome 122.0.6261.57 (r1250580) ([#11958](https://github.com/puppeteer/puppeteer/issues/11958)) ([70ad3b2](https://github.com/puppeteer/puppeteer/commit/70ad3b244826ca102737e93cd2316e451ea310e8)) + + +### Bug Fixes + +* deprecate isIncognito ([#11962](https://github.com/puppeteer/puppeteer/issues/11962)) ([ceab7a9](https://github.com/puppeteer/puppeteer/commit/ceab7a9042fe5fc3f71875e75327bb370f1c43a5)) +* roll to Chrome 121.0.6167.184 (r1233107) ([#11948](https://github.com/puppeteer/puppeteer/issues/11948)) ([03ef7a6](https://github.com/puppeteer/puppeteer/commit/03ef7a62c23f2339e4d508d9abfe0894bd790cdd)) +* update touchscreen tests ([#11960](https://github.com/puppeteer/puppeteer/issues/11960)) ([013bd0b](https://github.com/puppeteer/puppeteer/commit/013bd0b12d3a69f9d62fffe7911a327ad26d33d8)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @puppeteer/browsers bumped from 2.0.1 to 2.1.0 + +## [22.1.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-core-v22.0.0...puppeteer-core-v22.1.0) (2024-02-17) + + +### Features + +* support closing workers ([#11870](https://github.com/puppeteer/puppeteer/issues/11870)) ([1bdae40](https://github.com/puppeteer/puppeteer/commit/1bdae40ec865326fcb365320939869a6efb18c8a)) + + +### Bug Fixes + +* Chrome for Testing downloads have a new URL ([#11923](https://github.com/puppeteer/puppeteer/issues/11923)) ([f00a94a](https://github.com/puppeteer/puppeteer/commit/f00a94a809d38ee1c2c8cfc8597c66db9f3d243d)) +* deprecate `Page.prototype.target` ([#11872](https://github.com/puppeteer/puppeteer/issues/11872)) ([15c986c](https://github.com/puppeteer/puppeteer/commit/15c986c2bc5f5005a738187674cd6c44bcb3df3d)) +* frameElement should work for framesets ([#11842](https://github.com/puppeteer/puppeteer/issues/11842)) ([c5cee0e](https://github.com/puppeteer/puppeteer/commit/c5cee0e37dec8b90a17bf13400ede7ebdf453ac8)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @puppeteer/browsers bumped from 2.0.0 to 2.0.1 + +## [22.0.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-core-v21.11.0...puppeteer-core-v22.0.0) (2024-02-05) + + +### âš BREAKING CHANGES + +* rename createIncognitoBrowserContext to createBrowserContext ([#11834](https://github.com/puppeteer/puppeteer/issues/11834)) +* enable the new-headless mode by default ([#11815](https://github.com/puppeteer/puppeteer/issues/11815)) +* remove networkConditions in favor of PredefinedNetworkConditions ([#11806](https://github.com/puppeteer/puppeteer/issues/11806)) +* use ReadableStreams ([#11805](https://github.com/puppeteer/puppeteer/issues/11805)) +* remove duplicate type names ([#11803](https://github.com/puppeteer/puppeteer/issues/11803)) +* remove add/removeEventListener in favor of on/off ([#11792](https://github.com/puppeteer/puppeteer/issues/11792)) +* make console warn level compatible with WebDriver BiDi ([#11790](https://github.com/puppeteer/puppeteer/issues/11790)) +* remove InterceptResolutionStrategy ([#11788](https://github.com/puppeteer/puppeteer/issues/11788)) +* remove devices in favor of KnownDevices ([#11787](https://github.com/puppeteer/puppeteer/issues/11787)) +* remove `$x` and `waitForXpath` ([#11782](https://github.com/puppeteer/puppeteer/issues/11782)) +* remove waitForTimeout ([#11780](https://github.com/puppeteer/puppeteer/issues/11780)) +* generate accessible PDFs by default ([#11778](https://github.com/puppeteer/puppeteer/issues/11778)) +* remove `error` const, change CustomError to PuppeteerError ([#11777](https://github.com/puppeteer/puppeteer/issues/11777)) +* remove viewport resizing from ElementHandle.screenshot ([#11774](https://github.com/puppeteer/puppeteer/issues/11774)) +* remove PUPPETEER_DOWNLOAD_PATH in favor of PUPPETEER_CACHE_DIR ([#11605](https://github.com/puppeteer/puppeteer/issues/11605)) +* BiDi cookies ([#11532](https://github.com/puppeteer/puppeteer/issues/11532)) +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) + +### Features + +* BiDi cookies ([#11532](https://github.com/puppeteer/puppeteer/issues/11532)) ([9cb1fde](https://github.com/puppeteer/puppeteer/commit/9cb1fde58949811532644decb79b691318031d8c)) +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) ([953f420](https://github.com/puppeteer/puppeteer/commit/953f4207b17210fa7231225e6f29a826f77e0832)) +* generate accessible PDFs by default ([#11778](https://github.com/puppeteer/puppeteer/issues/11778)) ([4fc1402](https://github.com/puppeteer/puppeteer/commit/4fc14026e9bfffeedf317e9b61c7cda8509091ba)) +* remove PUPPETEER_DOWNLOAD_PATH in favor of PUPPETEER_CACHE_DIR ([#11605](https://github.com/puppeteer/puppeteer/issues/11605)) ([4677281](https://github.com/puppeteer/puppeteer/commit/467728187737283191f6528676e50d53dae6e5ef)) + + +### Bug Fixes + +* make console warn level compatible with WebDriver BiDi ([#11790](https://github.com/puppeteer/puppeteer/issues/11790)) ([d4e9d8d](https://github.com/puppeteer/puppeteer/commit/d4e9d8d591e4fb1e2a33fe3a586a8beaccf263e8)) +* remove viewport resizing from ElementHandle.screenshot ([#11774](https://github.com/puppeteer/puppeteer/issues/11774)) ([ced2235](https://github.com/puppeteer/puppeteer/commit/ced2235ada95ad67227df0ce579070ccb501a47b)) + + +### Code Refactoring + +* enable the new-headless mode by default ([#11815](https://github.com/puppeteer/puppeteer/issues/11815)) ([75c9e11](https://github.com/puppeteer/puppeteer/commit/75c9e117f1bf0d7a4de82c79201d70bf3cee2b6f)) +* remove `$x` and `waitForXpath` ([#11782](https://github.com/puppeteer/puppeteer/issues/11782)) ([53c9134](https://github.com/puppeteer/puppeteer/commit/53c91348094dc0bce59086c98986c5d06a949d08)) +* remove `error` const, change CustomError to PuppeteerError ([#11777](https://github.com/puppeteer/puppeteer/issues/11777)) ([b3bfdd2](https://github.com/puppeteer/puppeteer/commit/b3bfdd2024097be1974e28b3766419189b4a9fe0)) +* remove add/removeEventListener in favor of on/off ([#11792](https://github.com/puppeteer/puppeteer/issues/11792)) ([f160874](https://github.com/puppeteer/puppeteer/commit/f1608743c83e8ce7b56aec98ccdddacc91b86179)) +* remove devices in favor of KnownDevices ([#11787](https://github.com/puppeteer/puppeteer/issues/11787)) ([eb360e3](https://github.com/puppeteer/puppeteer/commit/eb360e3a762d9232a4972d4ec877b7d57a5b60c7)) +* remove duplicate type names ([#11803](https://github.com/puppeteer/puppeteer/issues/11803)) ([514e2d5](https://github.com/puppeteer/puppeteer/commit/514e2d5241dc3a9027c96d739cfc99efc5a02783)) +* remove InterceptResolutionStrategy ([#11788](https://github.com/puppeteer/puppeteer/issues/11788)) ([f18d447](https://github.com/puppeteer/puppeteer/commit/f18d44761cd1acc2e6b867e5eb2ebd753854e9ea)) +* remove networkConditions in favor of PredefinedNetworkConditions ([#11806](https://github.com/puppeteer/puppeteer/issues/11806)) ([7564dfa](https://github.com/puppeteer/puppeteer/commit/7564dfa9110e44b1f50f5fb1543c5c7d8529c182)) +* remove waitForTimeout ([#11780](https://github.com/puppeteer/puppeteer/issues/11780)) ([1900fa9](https://github.com/puppeteer/puppeteer/commit/1900fa94183e0a8654633a91f82b372ad068da71)) +* rename createIncognitoBrowserContext to createBrowserContext ([#11834](https://github.com/puppeteer/puppeteer/issues/11834)) ([46a3ef2](https://github.com/puppeteer/puppeteer/commit/46a3ef2681456d604e775f578fa447a094200610)) +* use ReadableStreams ([#11805](https://github.com/puppeteer/puppeteer/issues/11805)) ([84d9a94](https://github.com/puppeteer/puppeteer/commit/84d9a94d6228800e9f80914472ff2e5a4ee71b18)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @puppeteer/browsers bumped from 1.9.1 to 2.0.0 + +## [21.11.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-core-v21.10.0...puppeteer-core-v21.11.0) (2024-02-02) + + +### Features + +* add outline to PDF generation ([#11779](https://github.com/puppeteer/puppeteer/issues/11779)) ([b99d478](https://github.com/puppeteer/puppeteer/commit/b99d478cd48adc261878836e04eac55ecc2890f2)) +* **bidi:** implement UserContexts ([#11784](https://github.com/puppeteer/puppeteer/issues/11784)) ([2930a70](https://github.com/puppeteer/puppeteer/commit/2930a70c884ce6835ec6bcff27b32f7d273c8af0)) + + +### Bug Fixes + +* use shareReplay for inflight requests ([#11810](https://github.com/puppeteer/puppeteer/issues/11810)) ([0f0813d](https://github.com/puppeteer/puppeteer/commit/0f0813db38aa0eb14d7514d725852d0cb66f4f0e)) + ## [21.10.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-core-v21.9.0...puppeteer-core-v21.10.0) (2024-01-29) diff --git a/remote/test/puppeteer/packages/puppeteer-core/Herebyfile.mjs b/remote/test/puppeteer/packages/puppeteer-core/Herebyfile.mjs index 723fa2868a..972a080ba0 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/Herebyfile.mjs +++ b/remote/test/puppeteer/packages/puppeteer-core/Herebyfile.mjs @@ -1,10 +1,19 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {mkdir, readFile, readdir, writeFile} from 'fs/promises'; -import {join} from 'path/posix'; +import Module from 'node:module'; +import path from 'path'; +import posixPath from 'path/posix'; import esbuild from 'esbuild'; import {execa} from 'execa'; import {task} from 'hereby'; +const require = Module.createRequire(import.meta.url); + export const generateVersionTask = task({ name: 'generate:version', run: async () => { @@ -91,20 +100,52 @@ export const buildTask = task({ }); const builders = []; for (const format of formats) { - const folder = join('lib', format, 'third_party'); + const folder = posixPath.join('lib', format, 'third_party'); for (const name of packages) { - const path = join(folder, name, `${name}.js`); + const entrypoint = posixPath.join(folder, name, `${name}.js`); builders.push( await esbuild.build({ - entryPoints: [path], - outfile: path, + entryPoints: [entrypoint], + outfile: entrypoint, bundle: true, allowOverwrite: true, format, target: 'node16', minify: true, + legalComments: 'inline', }) ); + let license = ''; + switch (name) { + case 'rxjs': + license = await readFile( + path.join( + path.dirname(require.resolve('rxjs')), + '..', + '..', + 'LICENSE.txt' + ), + 'utf-8' + ); + break; + case 'mitt': + license = await readFile( + path.join(path.dirname(require.resolve('mitt')), '..', 'LICENSE'), + 'utf-8' + ); + break; + default: + throw new Error(`Add license handling for ${path}`); + } + const content = await readFile(entrypoint, 'utf-8'); + await writeFile( + entrypoint, + `/** +${license} +*/ +${content}`, + 'utf-8' + ); } } await Promise.all(builders); diff --git a/remote/test/puppeteer/packages/puppeteer-core/package.json b/remote/test/puppeteer/packages/puppeteer-core/package.json index 2f1943bd2f..1d4d564c4f 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/package.json +++ b/remote/test/puppeteer/packages/puppeteer-core/package.json @@ -1,6 +1,6 @@ { "name": "puppeteer-core", - "version": "21.10.0", + "version": "22.4.0", "description": "A high-level API to control headless Chrome over the DevTools Protocol", "keywords": [ "puppeteer", @@ -31,13 +31,13 @@ "url": "https://github.com/puppeteer/puppeteer/tree/main/packages/puppeteer-core" }, "engines": { - "node": ">=16.13.2" + "node": ">=18" }, "scripts": { "build:docs": "wireit", "build": "wireit", "check": "tsx tools/ensure-correct-devtools-protocol-package", - "clean": "../../tools/clean.js", + "clean": "../../tools/clean.mjs", "prepack": "wireit", "unit": "wireit" }, @@ -77,7 +77,8 @@ "files": [ "{src,third_party}/**", "../../versions.js", - "!src/generated" + "!src/generated", + "Herebyfile.mjs" ], "output": [ "lib/{cjs,esm}/**" @@ -118,11 +119,11 @@ "author": "The Chromium Authors", "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "1.9.1", - "chromium-bidi": "0.5.6", + "@puppeteer/browsers": "2.1.0", + "chromium-bidi": "0.5.12", "cross-fetch": "4.0.0", "debug": "4.3.4", - "devtools-protocol": "0.0.1232444", + "devtools-protocol": "0.0.1249869", "ws": "8.16.0" }, "devDependencies": { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/Browser.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/Browser.ts index e3b465c80e..6d7ea19d49 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/Browser.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/Browser.ts @@ -9,7 +9,6 @@ import type {ChildProcess} from 'child_process'; import type {Protocol} from 'devtools-protocol'; import { - filterAsync, firstValueFrom, from, merge, @@ -17,7 +16,12 @@ import { } from '../../third_party/rxjs/rxjs.js'; import type {ProtocolType} from '../common/ConnectOptions.js'; import {EventEmitter, type EventType} from '../common/EventEmitter.js'; -import {debugError, fromEmitterEvent, timeout} from '../common/util.js'; +import { + debugError, + fromEmitterEvent, + filterAsync, + timeout, +} from '../common/util.js'; import {asyncDisposeSymbol, disposeSymbol} from '../util/disposable.js'; import type {BrowserContext} from './BrowserContext.js'; @@ -136,7 +140,7 @@ export const enum BrowserEvent { * Emitted when the URL of a target changes. Contains a {@link Target} * instance. * - * @remarks Note that this includes target changes in incognito browser + * @remarks Note that this includes target changes in all browser * contexts. */ TargetChanged = 'targetchanged', @@ -147,7 +151,7 @@ export const enum BrowserEvent { * * Contains a {@link Target} instance. * - * @remarks Note that this includes target creations in incognito browser + * @remarks Note that this includes target creations in all browser * contexts. */ TargetCreated = 'targetcreated', @@ -155,7 +159,7 @@ export const enum BrowserEvent { * Emitted when a target is destroyed, for example when a page is closed. * Contains a {@link Target} instance. * - * @remarks Note that this includes target destructions in incognito browser + * @remarks Note that this includes target destructions in all browser * contexts. */ TargetDestroyed = 'targetdestroyed', @@ -165,13 +169,6 @@ export const enum BrowserEvent { TargetDiscovered = 'targetdiscovered', } -export { - /** - * @deprecated Use {@link BrowserEvent}. - */ - BrowserEvent as BrowserEmittedEvents, -}; - /** * @public */ @@ -251,7 +248,7 @@ export abstract class Browser extends EventEmitter<BrowserEvents> { abstract process(): ChildProcess | null; /** - * Creates a new incognito {@link BrowserContext | browser context}. + * Creates a new {@link BrowserContext | browser context}. * * This won't share cookies/cache with other {@link BrowserContext | browser contexts}. * @@ -261,15 +258,15 @@ export abstract class Browser extends EventEmitter<BrowserEvents> { * import puppeteer from 'puppeteer'; * * const browser = await puppeteer.launch(); - * // Create a new incognito browser context. - * const context = await browser.createIncognitoBrowserContext(); + * // Create a new browser context. + * const context = await browser.createBrowserContext(); * // Create a new page in a pristine context. * const page = await context.newPage(); * // Do stuff * await page.goto('https://example.com'); * ``` */ - abstract createIncognitoBrowserContext( + abstract createBrowserContext( options?: BrowserContextOptions ): Promise<BrowserContext>; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/BrowserContext.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/BrowserContext.ts index 79335eb9ed..5e6a5d5d5c 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/BrowserContext.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/BrowserContext.ts @@ -4,8 +4,19 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { + firstValueFrom, + from, + merge, + raceWith, +} from '../../third_party/rxjs/rxjs.js'; import {EventEmitter, type EventType} from '../common/EventEmitter.js'; -import {debugError} from '../common/util.js'; +import { + debugError, + fromEmitterEvent, + filterAsync, + timeout, +} from '../common/util.js'; import {asyncDisposeSymbol, disposeSymbol} from '../util/disposable.js'; import type {Browser, Permission, WaitForTargetOptions} from './Browser.js'; @@ -38,13 +49,6 @@ export const enum BrowserContextEvent { TargetDestroyed = 'targetdestroyed', } -export { - /** - * @deprecated Use {@link BrowserContextEvent} - */ - BrowserContextEvent as BrowserContextEmittedEvents, -}; - /** * @public */ @@ -55,12 +59,13 @@ export interface BrowserContextEvents extends Record<EventType, unknown> { } /** - * {@link BrowserContext} represents individual sessions within a + * {@link BrowserContext} represents individual user contexts within a * {@link Browser | browser}. * * When a {@link Browser | browser} is launched, it has a single * {@link BrowserContext | browser context} by default. Others can be created - * using {@link Browser.createIncognitoBrowserContext}. + * using {@link Browser.createBrowserContext}. Each context has isolated storage + * (cookies/localStorage/etc.) * * {@link BrowserContext} {@link EventEmitter | emits} various events which are * documented in the {@link BrowserContextEvent} enum. @@ -69,11 +74,11 @@ export interface BrowserContextEvents extends Record<EventType, unknown> { * `window.open`, the popup will belong to the parent {@link Page.browserContext * | page's browser context}. * - * @example Creating an incognito {@link BrowserContext | browser context}: + * @example Creating a new {@link BrowserContext | browser context}: * * ```ts - * // Create a new incognito browser context - * const context = await browser.createIncognitoBrowserContext(); + * // Create a new browser context + * const context = await browser.createBrowserContext(); * // Create a new page inside context. * const page = await context.newPage(); * // ... do stuff with page ... @@ -114,10 +119,19 @@ export abstract class BrowserContext extends EventEmitter<BrowserContextEvents> * ); * ``` */ - abstract waitForTarget( + async waitForTarget( predicate: (x: Target) => boolean | Promise<boolean>, - options?: WaitForTargetOptions - ): Promise<Target>; + options: WaitForTargetOptions = {} + ): Promise<Target> { + const {timeout: ms = 30000} = options; + return await firstValueFrom( + merge( + fromEmitterEvent(this, BrowserContextEvent.TargetCreated), + fromEmitterEvent(this, BrowserContextEvent.TargetChanged), + from(this.targets()) + ).pipe(filterAsync(predicate), raceWith(timeout(ms))) + ); + } /** * Gets a list of all open {@link Page | pages} inside this @@ -131,8 +145,20 @@ export abstract class BrowserContext extends EventEmitter<BrowserContextEvents> /** * Whether this {@link BrowserContext | browser context} is incognito. * - * The {@link Browser.defaultBrowserContext | default browser context} is the - * only non-incognito browser context. + * In Chrome, the + * {@link Browser.defaultBrowserContext | default browser context} is the only + * non-incognito browser context. + * + * @deprecated In Chrome, the + * {@link Browser.defaultBrowserContext | default browser context} can also be + * "icognito" if configured via the arguments and in such cases this getter + * returns wrong results (see + * https://github.com/puppeteer/puppeteer/issues/8836). Also, the term + * "incognito" is not applicable to other browsers. To migrate, check the + * {@link Browser.defaultBrowserContext | default browser context} instead: in + * Chrome all non-default contexts are incognito, and the default context + * might be incognito if you provide the `--incognito` argument when launching + * the browser. */ abstract isIncognito(): boolean; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/CDPSession.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/CDPSession.ts index 8bdf96f954..3a1fdf1e24 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/CDPSession.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/CDPSession.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import type {ProtocolMapping} from 'devtools-protocol/types/protocol-mapping.js'; import type {Connection} from '../cdp/Connection.js'; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/ElementHandle.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/ElementHandle.ts index 43fec58e37..9b1326f998 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/ElementHandle.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/ElementHandle.ts @@ -17,15 +17,10 @@ import type { NodeFor, } from '../common/types.js'; import type {KeyInput} from '../common/USKeyboardLayout.js'; -import { - debugError, - isString, - withSourcePuppeteerURLIfNone, -} from '../common/util.js'; +import {isString, withSourcePuppeteerURLIfNone} from '../common/util.js'; import {assert} from '../util/assert.js'; import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js'; import {throwIfDisposed} from '../util/decorators.js'; -import {AsyncDisposableStack} from '../util/disposable.js'; import {_isElementHandle} from './ElementHandleSymbol.js'; import type { @@ -482,27 +477,6 @@ export abstract class ElementHandle< } /** - * @deprecated Use {@link ElementHandle.$$} with the `xpath` prefix. - * - * Example: `await elementHandle.$$('xpath/' + xpathExpression)` - * - * The method evaluates the XPath expression relative to the elementHandle. - * If `xpath` starts with `//` instead of `.//`, the dot will be appended - * automatically. - * - * If there are no such elements, the method will resolve to an empty array. - * @param expression - Expression to {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate | evaluate} - */ - @throwIfDisposed() - @ElementHandle.bindIsolatedHandle - async $x(expression: string): Promise<Array<ElementHandle<Node>>> { - if (expression.startsWith('//')) { - expression = `.${expression}`; - } - return await this.$$(`xpath/${expression}`); - } - - /** * Wait for an element matching the given selector to appear in the current * element. * @@ -587,84 +561,6 @@ export abstract class ElementHandle< } /** - * @deprecated Use {@link ElementHandle.waitForSelector} with the `xpath` - * prefix. - * - * Example: `await elementHandle.waitForSelector('xpath/' + xpathExpression)` - * - * The method evaluates the XPath expression relative to the elementHandle. - * - * Wait for the `xpath` within the element. If at the moment of calling the - * method the `xpath` already exists, the method will return immediately. If - * the `xpath` doesn't appear after the `timeout` milliseconds of waiting, the - * function will throw. - * - * If `xpath` starts with `//` instead of `.//`, the dot will be appended - * automatically. - * - * @example - * This method works across navigation. - * - * ```ts - * import puppeteer from 'puppeteer'; - * (async () => { - * const browser = await puppeteer.launch(); - * const page = await browser.newPage(); - * let currentURL; - * page - * .waitForXPath('//img') - * .then(() => console.log('First URL with image: ' + currentURL)); - * for (currentURL of [ - * 'https://example.com', - * 'https://google.com', - * 'https://bbc.com', - * ]) { - * await page.goto(currentURL); - * } - * await browser.close(); - * })(); - * ``` - * - * @param xpath - A - * {@link https://developer.mozilla.org/en-US/docs/Web/XPath | xpath} of an - * element to wait for - * @param options - Optional waiting parameters - * @returns Promise which resolves when element specified by xpath string is - * added to DOM. Resolves to `null` if waiting for `hidden: true` and xpath is - * not found in DOM, otherwise resolves to `ElementHandle`. - * @remarks - * The optional Argument `options` have properties: - * - * - `visible`: A boolean to wait for element to be present in DOM and to be - * visible, i.e. to not have `display: none` or `visibility: hidden` CSS - * properties. Defaults to `false`. - * - * - `hidden`: A boolean wait for element to not be found in the DOM or to be - * hidden, i.e. have `display: none` or `visibility: hidden` CSS properties. - * Defaults to `false`. - * - * - `timeout`: A number which is maximum time to wait for in milliseconds. - * Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The - * default value can be changed by using the {@link Page.setDefaultTimeout} - * method. - */ - @throwIfDisposed() - @ElementHandle.bindIsolatedHandle - async waitForXPath( - xpath: string, - options: { - visible?: boolean; - hidden?: boolean; - timeout?: number; - } = {} - ): Promise<ElementHandle<Node> | null> { - if (xpath.startsWith('//')) { - xpath = `.${xpath}`; - } - return await this.waitForSelector(`xpath/${xpath}`, options); - } - - /** * Converts the current handle to the given element type. * * @example @@ -1346,30 +1242,6 @@ export abstract class ElementHandle< const page = this.frame.page(); - // If the element is larger than the viewport, `captureBeyondViewport` will - // _not_ affect element rendering, so we need to adjust the viewport to - // properly render the element. - const viewport = page.viewport() ?? { - width: clip.width, - height: clip.height, - }; - await using stack = new AsyncDisposableStack(); - if (clip.width > viewport.width || clip.height > viewport.height) { - await this.frame.page().setViewport({ - ...viewport, - width: Math.max(viewport.width, Math.ceil(clip.width)), - height: Math.max(viewport.height, Math.ceil(clip.height)), - }); - - stack.defer(async () => { - try { - await this.frame.page().setViewport(viewport); - } catch (error) { - debugError(error); - } - }); - } - // Only scroll the element into view if the user wants it. if (scrollIntoView) { await this.scrollIntoViewIfNeeded(); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/Frame.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/Frame.ts index 757ec872c6..19b5eb7fa0 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/Frame.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/Frame.ts @@ -14,7 +14,6 @@ import type { WaitTimeoutOptions, } from '../api/Page.js'; import type {DeviceRequestPrompt} from '../cdp/DeviceRequestPrompt.js'; -import type {IsolatedWorldChart} from '../cdp/IsolatedWorld.js'; import type {PuppeteerLifeCycleEvent} from '../cdp/LifecycleWatcher.js'; import {EventEmitter, type EventType} from '../common/EventEmitter.js'; import {getQueryHandlerAndSelector} from '../common/GetQueryHandler.js'; @@ -38,8 +37,8 @@ import type {CDPSession} from './CDPSession.js'; import type {KeyboardTypeOptions} from './Input.js'; import { FunctionLocator, - type Locator, NodeLocator, + type Locator, } from './locators/locators.js'; import type {Realm} from './Realm.js'; @@ -273,11 +272,6 @@ export abstract class Frame extends EventEmitter<FrameEvents> { /** * @internal */ - worlds!: IsolatedWorldChart; - - /** - * @internal - */ _name?: string; /** @@ -339,12 +333,7 @@ export abstract class Frame extends EventEmitter<FrameEvents> { */ abstract goto( url: string, - options?: { - referer?: string; - referrerPolicy?: string; - timeout?: number; - waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[]; - } + options?: GoToOptions ): Promise<HTTPResponse | null>; /** @@ -425,12 +414,12 @@ export abstract class Frame extends EventEmitter<FrameEvents> { return null; } using list = await parentFrame.isolatedRealm().evaluateHandle(() => { - return document.querySelectorAll('iframe'); + return document.querySelectorAll('iframe,frame'); }); for await (using iframe of transposeIterableHandle(list)) { const frame = await iframe.contentFrame(); - if (frame._id === this._id) { - return iframe.move(); + if (frame?._id === this._id) { + return (iframe as HandleFor<HTMLIFrameElement>).move(); } } return null; @@ -624,23 +613,6 @@ export abstract class Frame extends EventEmitter<FrameEvents> { } /** - * @deprecated Use {@link Frame.$$} with the `xpath` prefix. - * - * Example: `await frame.$$('xpath/' + xpathExpression)` - * - * This method evaluates the given XPath expression and returns the results. - * If `xpath` starts with `//` instead of `.//`, the dot will be appended - * automatically. - * @param expression - the XPath expression to evaluate. - */ - @throwIfDetached - async $x(expression: string): Promise<Array<ElementHandle<Node>>> { - // eslint-disable-next-line rulesdir/use-using -- This is cached. - const document = await this.#document(); - return await document.$x(expression); - } - - /** * Waits for an element matching the given selector to appear in the frame. * * This method works across navigations. @@ -690,39 +662,6 @@ export abstract class Frame extends EventEmitter<FrameEvents> { } /** - * @deprecated Use {@link Frame.waitForSelector} with the `xpath` prefix. - * - * Example: `await frame.waitForSelector('xpath/' + xpathExpression)` - * - * The method evaluates the XPath expression relative to the Frame. - * If `xpath` starts with `//` instead of `.//`, the dot will be appended - * automatically. - * - * Wait for the `xpath` to appear in page. If at the moment of calling the - * method the `xpath` already exists, the method will return immediately. If - * the xpath doesn't appear after the `timeout` milliseconds of waiting, the - * function will throw. - * - * For a code example, see the example for {@link Frame.waitForSelector}. That - * function behaves identically other than taking a CSS selector rather than - * an XPath. - * - * @param xpath - the XPath expression to wait for. - * @param options - options to configure the visibility of the element and how - * long to wait before timing out. - */ - @throwIfDetached - async waitForXPath( - xpath: string, - options: WaitForSelectorOptions = {} - ): Promise<ElementHandle<Node> | null> { - if (xpath.startsWith('//')) { - xpath = `.${xpath}`; - } - return await this.waitForSelector(`xpath/${xpath}`, options); - } - - /** * @example * The `waitForFunction` can be used to observe viewport size change: * @@ -799,13 +738,7 @@ export abstract class Frame extends EventEmitter<FrameEvents> { * @param options - Options to configure how long before timing out and at * what point to consider the content setting successful. */ - abstract setContent( - html: string, - options?: { - timeout?: number; - waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[]; - } - ): Promise<void>; + abstract setContent(html: string, options?: WaitForOptions): Promise<void>; /** * @internal @@ -1152,32 +1085,6 @@ export abstract class Frame extends EventEmitter<FrameEvents> { } /** - * @deprecated Replace with `new Promise(r => setTimeout(r, milliseconds));`. - * - * Causes your script to wait for the given number of milliseconds. - * - * @remarks - * It's generally recommended to not wait for a number of seconds, but instead - * use {@link Frame.waitForSelector}, {@link Frame.waitForXPath} or - * {@link Frame.waitForFunction} to wait for exactly the conditions you want. - * - * @example - * - * Wait for 1 second: - * - * ```ts - * await frame.waitForTimeout(1000); - * ``` - * - * @param milliseconds - the number of milliseconds to wait. - */ - async waitForTimeout(milliseconds: number): Promise<void> { - return await new Promise(resolve => { - setTimeout(resolve, milliseconds); - }); - } - - /** * The frame's title. */ @throwIfDetached diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/HTTPRequest.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/HTTPRequest.ts index 3c952371ee..d72f088686 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/HTTPRequest.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/HTTPRequest.ts @@ -94,7 +94,8 @@ export abstract class HTTPRequest { /** * @internal */ - _requestId = ''; + abstract get id(): string; + /** * @internal */ @@ -395,13 +396,6 @@ export enum InterceptResolutionAction { /** * @public - * - * @deprecated please use {@link InterceptResolutionAction} instead. - */ -export type InterceptResolutionStrategy = InterceptResolutionAction; - -/** - * @public */ export type ErrorCode = | 'aborted' diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/Page.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/Page.ts index deb04628fd..b094d14b2f 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/Page.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/Page.ts @@ -4,26 +4,25 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {Readable} from 'stream'; - import type {Protocol} from 'devtools-protocol'; import { concat, EMPTY, filter, - filterAsync, first, firstValueFrom, from, map, merge, mergeMap, + mergeScan, of, - race, raceWith, + ReplaySubject, startWith, switchMap, + take, takeUntil, timer, type Observable, @@ -36,6 +35,11 @@ import type {DeviceRequestPrompt} from '../cdp/DeviceRequestPrompt.js'; import type {Credentials, NetworkConditions} from '../cdp/NetworkManager.js'; import type {Tracing} from '../cdp/Tracing.js'; import type {ConsoleMessage} from '../common/ConsoleMessage.js'; +import type { + Cookie, + CookieParam, + DeleteCookiesRequest, +} from '../common/Cookie.js'; import type {Device} from '../common/Device.js'; import {TargetCloseError} from '../common/Errors.js'; import { @@ -58,6 +62,7 @@ import type { import { debugError, fromEmitterEvent, + filterAsync, importFSPromises, isString, NETWORK_IDLE_TIME, @@ -477,15 +482,6 @@ export const enum PageEvent { WorkerDestroyed = 'workerdestroyed', } -export { - /** - * All the events that a page instance may emit. - * - * @deprecated Use {@link PageEvent}. - */ - PageEvent as PageEmittedEvents, -}; - /** * Denotes the objects received by callback functions for page events. * @@ -516,13 +512,6 @@ export interface PageEvents extends Record<EventType, unknown> { [PageEvent.WorkerDestroyed]: WebWorker; } -export type { - /** - * @deprecated Use {@link PageEvents}. - */ - PageEvents as PageEventObject, -}; - /** * @public */ @@ -604,8 +593,7 @@ export abstract class Page extends EventEmitter<PageEvents> { #requestHandlers = new WeakMap<Handler<HTTPRequest>, Handler<HTTPRequest>>(); - #requestsInFlight = 0; - #inflight$: Observable<number>; + #inflight$ = new ReplaySubject<number>(1); /** * @internal @@ -613,39 +601,37 @@ export abstract class Page extends EventEmitter<PageEvents> { constructor() { super(); - this.#inflight$ = fromEmitterEvent(this, PageEvent.Request).pipe( - takeUntil(fromEmitterEvent(this, PageEvent.Close)), - mergeMap(request => { - return concat( - of(1), - race( - fromEmitterEvent(this, PageEvent.Response).pipe( - filter(response => { - return response.request()._requestId === request._requestId; - }) - ), - fromEmitterEvent(this, PageEvent.RequestFailed).pipe( - filter(failure => { - return failure._requestId === request._requestId; - }) - ), - fromEmitterEvent(this, PageEvent.RequestFinished).pipe( - filter(success => { - return success._requestId === request._requestId; + fromEmitterEvent(this, PageEvent.Request) + .pipe( + mergeMap(originalRequest => { + return concat( + of(1), + merge( + fromEmitterEvent(this, PageEvent.RequestFailed), + fromEmitterEvent(this, PageEvent.RequestFinished), + fromEmitterEvent(this, PageEvent.Response).pipe( + map(response => { + return response.request(); + }) + ) + ).pipe( + filter(request => { + return request.id === originalRequest.id; + }), + take(1), + map(() => { + return -1; }) ) - ).pipe( - map(() => { - return -1; - }) - ) - ); - }) - ); - - this.#inflight$.subscribe(count => { - this.#requestsInFlight += count; - }); + ); + }), + mergeScan((acc, addend) => { + return of(acc + addend); + }, 0), + takeUntil(fromEmitterEvent(this, PageEvent.Close)), + startWith(0) + ) + .subscribe(this.#inflight$); } /** @@ -771,6 +757,8 @@ export abstract class Page extends EventEmitter<PageEvents> { /** * A target this page was created from. + * + * @deprecated Use {@link Page.createCDPSession} directly. */ abstract target(): Target; @@ -1287,28 +1275,12 @@ export abstract class Page extends EventEmitter<PageEvents> { } /** - * The method evaluates the XPath expression relative to the page document as - * its context node. If there are no such elements, the method resolves to an - * empty array. - * - * @remarks - * Shortcut for {@link Frame.$x | Page.mainFrame().$x(expression) }. - * - * @param expression - Expression to evaluate - */ - async $x(expression: string): Promise<Array<ElementHandle<Node>>> { - return await this.mainFrame().$x(expression); - } - - /** * If no URLs are specified, this method returns cookies for the current page * URL. If URLs are specified, only cookies for those URLs are returned. */ - abstract cookies(...urls: string[]): Promise<Protocol.Network.Cookie[]>; + abstract cookies(...urls: string[]): Promise<Cookie[]>; - abstract deleteCookie( - ...cookies: Protocol.Network.DeleteCookiesRequest[] - ): Promise<void>; + abstract deleteCookie(...cookies: DeleteCookiesRequest[]): Promise<void>; /** * @example @@ -1317,7 +1289,7 @@ export abstract class Page extends EventEmitter<PageEvents> { * await page.setCookie(cookieObject1, cookieObject2); * ``` */ - abstract setCookie(...cookies: Protocol.Network.CookieParam[]): Promise<void>; + abstract setCookie(...cookies: CookieParam[]): Promise<void>; /** * Adds a `<script>` tag into the page with the desired URL or content. @@ -1776,13 +1748,11 @@ export abstract class Page extends EventEmitter<PageEvents> { } = options; return this.#inflight$.pipe( - startWith(this.#requestsInFlight), - switchMap(() => { - if (this.#requestsInFlight > concurrency) { + switchMap(inflight => { + if (inflight > concurrency) { return EMPTY; - } else { - return timer(idleTime); } + return timer(idleTime); }), map(() => {}), raceWith( @@ -2604,7 +2574,9 @@ export abstract class Page extends EventEmitter<PageEvents> { * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-print-color-adjust | `-webkit-print-color-adjust`} * property to force rendering of exact colors. */ - abstract createPDFStream(options?: PDFOptions): Promise<Readable>; + abstract createPDFStream( + options?: PDFOptions + ): Promise<ReadableStream<Uint8Array>>; /** * {@inheritDoc Page.createPDFStream} @@ -2785,31 +2757,6 @@ export abstract class Page extends EventEmitter<PageEvents> { } /** - * @deprecated Replace with `new Promise(r => setTimeout(r, milliseconds));`. - * - * Causes your script to wait for the given number of milliseconds. - * - * @remarks - * - * It's generally recommended to not wait for a number of seconds, but instead - * use {@link Frame.waitForSelector}, {@link Frame.waitForXPath} or - * {@link Frame.waitForFunction} to wait for exactly the conditions you want. - * - * @example - * - * Wait for 1 second: - * - * ```ts - * await page.waitForTimeout(1000); - * ``` - * - * @param milliseconds - the number of milliseconds to wait. - */ - waitForTimeout(milliseconds: number): Promise<void> { - return this.mainFrame().waitForTimeout(milliseconds); - } - - /** * Wait for the `selector` to appear in page. If at the moment of calling the * method the `selector` already exists, the method will return immediately. If * the `selector` doesn't appear after the `timeout` milliseconds of waiting, the @@ -2869,64 +2816,6 @@ export abstract class Page extends EventEmitter<PageEvents> { } /** - * Wait for the `xpath` to appear in page. If at the moment of calling the - * method the `xpath` already exists, the method will return immediately. If - * the `xpath` doesn't appear after the `timeout` milliseconds of waiting, the - * function will throw. - * - * @example - * This method works across navigation - * - * ```ts - * import puppeteer from 'puppeteer'; - * (async () => { - * const browser = await puppeteer.launch(); - * const page = await browser.newPage(); - * let currentURL; - * page - * .waitForXPath('//img') - * .then(() => console.log('First URL with image: ' + currentURL)); - * for (currentURL of [ - * 'https://example.com', - * 'https://google.com', - * 'https://bbc.com', - * ]) { - * await page.goto(currentURL); - * } - * await browser.close(); - * })(); - * ``` - * - * @param xpath - A - * {@link https://developer.mozilla.org/en-US/docs/Web/XPath | xpath} of an - * element to wait for - * @param options - Optional waiting parameters - * @returns Promise which resolves when element specified by xpath string is - * added to DOM. Resolves to `null` if waiting for `hidden: true` and xpath is - * not found in DOM, otherwise resolves to `ElementHandle`. - * @remarks - * The optional Argument `options` have properties: - * - * - `visible`: A boolean to wait for element to be present in DOM and to be - * visible, i.e. to not have `display: none` or `visibility: hidden` CSS - * properties. Defaults to `false`. - * - * - `hidden`: A boolean wait for element to not be found in the DOM or to be - * hidden, i.e. have `display: none` or `visibility: hidden` CSS properties. - * Defaults to `false`. - * - * - `timeout`: A number which is maximum time to wait for in milliseconds. - * Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default - * value can be changed by using the {@link Page.setDefaultTimeout} method. - */ - waitForXPath( - xpath: string, - options?: WaitForSelectorOptions - ): Promise<ElementHandle<Node> | null> { - return this.mainFrame().waitForXPath(xpath, options); - } - - /** * Waits for the provided function, `pageFunction`, to return a truthy value when * evaluated in the page's context. * diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/WebWorker.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/WebWorker.ts index 4de287f146..b65452b650 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/WebWorker.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/WebWorker.ts @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import {UnsupportedOperation} from '../common/Errors.js'; import {EventEmitter, type EventType} from '../common/EventEmitter.js'; import {TimeoutSettings} from '../common/TimeoutSettings.js'; import type {EvaluateFunc, HandleFor} from '../common/types.js'; @@ -131,4 +132,8 @@ export abstract class WebWorker extends EventEmitter< func = withSourcePuppeteerURLIfNone(this.evaluateHandle.name, func); return await this.mainRealm().evaluateHandle(func, ...args); } + + async close(): Promise<void> { + throw new UnsupportedOperation('WebWorker.close() is not supported'); + } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/locators/locators.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/locators/locators.ts index 7bec11e38e..d88cc0a17d 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/locators/locators.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/locators/locators.ts @@ -109,24 +109,14 @@ export enum LocatorEvent { */ Action = 'action', } -export { - /** - * @deprecated Use {@link LocatorEvent}. - */ - LocatorEvent as LocatorEmittedEvents, -}; + /** * @public */ export interface LocatorEvents extends Record<EventType, unknown> { [LocatorEvent.Action]: undefined; } -export type { - /** - * @deprecated Use {@link LocatorEvents}. - */ - LocatorEvents as LocatorEventObject, -}; + /** * Locators describe a strategy of locating objects and performing an action on * them. If the action fails because the object is not ready for the action, the diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Browser.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Browser.ts index 42979790c9..8798d8325d 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Browser.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Browser.ts @@ -8,6 +8,7 @@ import type {ChildProcess} from 'child_process'; import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; +import type {BrowserEvents} from '../api/Browser.js'; import { Browser, BrowserEvent, @@ -19,22 +20,17 @@ import {BrowserContextEvent} from '../api/BrowserContext.js'; import type {Page} from '../api/Page.js'; import type {Target} from '../api/Target.js'; import {UnsupportedOperation} from '../common/Errors.js'; -import type {Handler} from '../common/EventEmitter.js'; +import {EventEmitter} from '../common/EventEmitter.js'; import {debugError} from '../common/util.js'; import type {Viewport} from '../common/Viewport.js'; +import {bubble} from '../util/decorators.js'; import {BidiBrowserContext} from './BrowserContext.js'; -import {BrowsingContext, BrowsingContextEvent} from './BrowsingContext.js'; import type {BidiConnection} from './Connection.js'; import type {Browser as BrowserCore} from './core/Browser.js'; import {Session} from './core/Session.js'; import type {UserContext} from './core/UserContext.js'; -import { - BiDiBrowserTarget, - BiDiBrowsingContextTarget, - BiDiPageTarget, - type BidiTarget, -} from './Target.js'; +import {BidiBrowserTarget} from './Target.js'; /** * @internal @@ -89,28 +85,18 @@ export class BidiBrowser extends Browser { const browser = new BidiBrowser(session.browser, opts); browser.#initialize(); - await browser.#getTree(); return browser; } + @bubble() + accessor #trustedEmitter = new EventEmitter<BrowserEvents>(); + #process?: ChildProcess; #closeCallback?: BrowserCloseCallback; #browserCore: BrowserCore; #defaultViewport: Viewport | null; - #targets = new Map<string, BidiTarget>(); #browserContexts = new WeakMap<UserContext, BidiBrowserContext>(); - #browserTarget: BiDiBrowserTarget; - - #connectionEventHandlers = new Map< - Bidi.BrowsingContextEvent['method'], - Handler<any> - >([ - ['browsingContext.contextCreated', this.#onContextCreated.bind(this)], - ['browsingContext.contextDestroyed', this.#onContextDestroyed.bind(this)], - ['browsingContext.domContentLoaded', this.#onContextDomLoaded.bind(this)], - ['browsingContext.fragmentNavigated', this.#onContextNavigation.bind(this)], - ['browsingContext.navigationStarted', this.#onContextNavigation.bind(this)], - ]); + #target = new BidiBrowserTarget(this); private constructor(browserCore: BrowserCore, opts: BidiBrowserOptions) { super(); @@ -118,22 +104,22 @@ export class BidiBrowser extends Browser { this.#closeCallback = opts.closeCallback; this.#browserCore = browserCore; this.#defaultViewport = opts.defaultViewport; - this.#browserTarget = new BiDiBrowserTarget(this); - this.#createBrowserContext(this.#browserCore.defaultUserContext); } #initialize() { + // Initializing existing contexts. + for (const userContext of this.#browserCore.userContexts) { + this.#createBrowserContext(userContext); + } + this.#browserCore.once('disconnected', () => { - this.emit(BrowserEvent.Disconnected, undefined); + this.#trustedEmitter.emit(BrowserEvent.Disconnected, undefined); + this.#trustedEmitter.removeAllListeners(); }); this.#process?.once('close', () => { this.#browserCore.dispose('Browser process exited.', true); this.connection.dispose(); }); - - for (const [eventName, handler] of this.#connectionEventHandlers) { - this.connection.on(eventName, handler); - } } get #browserName() { @@ -143,82 +129,40 @@ export class BidiBrowser extends Browser { return this.#browserCore.session.capabilities.browserVersion; } + get cdpSupported(): boolean { + return !this.#browserName.toLocaleLowerCase().includes('firefox'); + } + override userAgent(): never { throw new UnsupportedOperation(); } #createBrowserContext(userContext: UserContext) { - const browserContext = new BidiBrowserContext(this, userContext, { + const browserContext = BidiBrowserContext.from(this, userContext, { defaultViewport: this.#defaultViewport, }); this.#browserContexts.set(userContext, browserContext); - return browserContext; - } - - #onContextDomLoaded(event: Bidi.BrowsingContext.Info) { - const target = this.#targets.get(event.context); - if (target) { - this.emit(BrowserEvent.TargetChanged, target); - } - } - - #onContextNavigation(event: Bidi.BrowsingContext.NavigationInfo) { - const target = this.#targets.get(event.context); - if (target) { - this.emit(BrowserEvent.TargetChanged, target); - target.browserContext().emit(BrowserContextEvent.TargetChanged, target); - } - } - #onContextCreated(event: Bidi.BrowsingContext.ContextCreated['params']) { - const context = new BrowsingContext( - this.connection, - event, - this.#browserName + browserContext.trustedEmitter.on( + BrowserContextEvent.TargetCreated, + target => { + this.#trustedEmitter.emit(BrowserEvent.TargetCreated, target); + } + ); + browserContext.trustedEmitter.on( + BrowserContextEvent.TargetChanged, + target => { + this.#trustedEmitter.emit(BrowserEvent.TargetChanged, target); + } + ); + browserContext.trustedEmitter.on( + BrowserContextEvent.TargetDestroyed, + target => { + this.#trustedEmitter.emit(BrowserEvent.TargetDestroyed, target); + } ); - this.connection.registerBrowsingContexts(context); - // TODO: once more browsing context types are supported, this should be - // updated to support those. Currently, all top-level contexts are treated - // as pages. - const browserContext = this.browserContexts().at(-1); - if (!browserContext) { - throw new Error('Missing browser contexts'); - } - const target = !context.parent - ? new BiDiPageTarget(browserContext, context) - : new BiDiBrowsingContextTarget(browserContext, context); - this.#targets.set(event.context, target); - - this.emit(BrowserEvent.TargetCreated, target); - target.browserContext().emit(BrowserContextEvent.TargetCreated, target); - - if (context.parent) { - const topLevel = this.connection.getTopLevelContext(context.parent); - topLevel.emit(BrowsingContextEvent.Created, context); - } - } - - async #getTree(): Promise<void> { - const {result} = await this.connection.send('browsingContext.getTree', {}); - for (const context of result.contexts) { - this.#onContextCreated(context); - } - } - async #onContextDestroyed( - event: Bidi.BrowsingContext.ContextDestroyed['params'] - ) { - const context = this.connection.getBrowsingContext(event.context); - const topLevelContext = this.connection.getTopLevelContext(event.context); - topLevelContext.emit(BrowsingContextEvent.Destroyed, context); - const target = this.#targets.get(event.context); - const page = await target?.page(); - await page?.close().catch(debugError); - this.#targets.delete(event.context); - if (target) { - this.emit(BrowserEvent.TargetDestroyed, target); - target.browserContext().emit(BrowserContextEvent.TargetDestroyed, target); - } + return browserContext; } get connection(): BidiConnection { @@ -231,9 +175,6 @@ export class BidiBrowser extends Browser { } override async close(): Promise<void> { - for (const [eventName, handler] of this.#connectionEventHandlers) { - this.connection.off(eventName, handler); - } if (this.connection.closed) { return; } @@ -250,14 +191,14 @@ export class BidiBrowser extends Browser { } override get connected(): boolean { - return !this.#browserCore.disposed; + return !this.#browserCore.disconnected; } override process(): ChildProcess | null { return this.#process ?? null; } - override async createIncognitoBrowserContext( + override async createBrowserContext( _options?: BrowserContextOptions ): Promise<BidiBrowserContext> { const userContext = await this.#browserCore.createUserContext(); @@ -283,19 +224,16 @@ export class BidiBrowser extends Browser { } override targets(): Target[] { - return [this.#browserTarget, ...Array.from(this.#targets.values())]; - } - - _getTargetById(id: string): BidiTarget { - const target = this.#targets.get(id); - if (!target) { - throw new Error('Target not found'); - } - return target; + return [ + this.#target, + ...this.browserContexts().flatMap(context => { + return context.targets(); + }), + ]; } - override target(): Target { - return this.#browserTarget; + override target(): BidiBrowserTarget { + return this.#target; } override async disconnect(): Promise<void> { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/BrowserContext.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/BrowserContext.ts index feb5e9951d..9976e4cc6a 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/BrowserContext.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/BrowserContext.ts @@ -6,18 +6,25 @@ import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; -import type {WaitForTargetOptions} from '../api/Browser.js'; -import {BrowserContext} from '../api/BrowserContext.js'; -import type {Page} from '../api/Page.js'; +import type {Permission} from '../api/Browser.js'; +import {WEB_PERMISSION_TO_PROTOCOL_PERMISSION} from '../api/Browser.js'; +import type {BrowserContextEvents} from '../api/BrowserContext.js'; +import {BrowserContext, BrowserContextEvent} from '../api/BrowserContext.js'; +import {PageEvent, type Page} from '../api/Page.js'; import type {Target} from '../api/Target.js'; -import {UnsupportedOperation} from '../common/Errors.js'; +import {EventEmitter} from '../common/EventEmitter.js'; import {debugError} from '../common/util.js'; import type {Viewport} from '../common/Viewport.js'; +import {bubble} from '../util/decorators.js'; import type {BidiBrowser} from './Browser.js'; -import type {BidiConnection} from './Connection.js'; +import type {BrowsingContext} from './core/BrowsingContext.js'; import {UserContext} from './core/UserContext.js'; -import type {BidiPage} from './Page.js'; +import type {BidiFrame} from './Frame.js'; +import {BidiPage} from './Page.js'; +import {BidiWorkerTarget} from './Target.js'; +import {BidiFrameTarget, BidiPageTarget} from './Target.js'; +import type {BidiWebWorker} from './WebWorker.js'; /** * @internal @@ -30,56 +37,134 @@ export interface BidiBrowserContextOptions { * @internal */ export class BidiBrowserContext extends BrowserContext { - #browser: BidiBrowser; - #connection: BidiConnection; - #defaultViewport: Viewport | null; - #userContext: UserContext; + static from( + browser: BidiBrowser, + userContext: UserContext, + options: BidiBrowserContextOptions + ): BidiBrowserContext { + const context = new BidiBrowserContext(browser, userContext, options); + context.#initialize(); + return context; + } + + @bubble() + accessor trustedEmitter = new EventEmitter<BrowserContextEvents>(); + + readonly #browser: BidiBrowser; + readonly #defaultViewport: Viewport | null; + // This is public because of cookies. + readonly userContext: UserContext; + readonly #pages = new WeakMap<BrowsingContext, BidiPage>(); + readonly #targets = new Map< + BidiPage, + [ + BidiPageTarget, + Map<BidiFrame | BidiWebWorker, BidiFrameTarget | BidiWorkerTarget>, + ] + >(); - constructor( + #overrides: Array<{origin: string; permission: Permission}> = []; + + private constructor( browser: BidiBrowser, userContext: UserContext, options: BidiBrowserContextOptions ) { super(); this.#browser = browser; - this.#userContext = userContext; - this.#connection = this.#browser.connection; + this.userContext = userContext; this.#defaultViewport = options.defaultViewport; } - override targets(): Target[] { - return this.#browser.targets().filter(target => { - return target.browserContext() === this; + #initialize() { + // Create targets for existing browsing contexts. + for (const browsingContext of this.userContext.browsingContexts) { + this.#createPage(browsingContext); + } + + this.userContext.on('browsingcontext', ({browsingContext}) => { + this.#createPage(browsingContext); + }); + this.userContext.on('closed', () => { + this.trustedEmitter.removeAllListeners(); }); } - override waitForTarget( - predicate: (x: Target) => boolean | Promise<boolean>, - options: WaitForTargetOptions = {} - ): Promise<Target> { - return this.#browser.waitForTarget(target => { - return target.browserContext() === this && predicate(target); - }, options); - } + #createPage(browsingContext: BrowsingContext): BidiPage { + const page = BidiPage.from(this, browsingContext); + this.#pages.set(browsingContext, page); + page.trustedEmitter.on(PageEvent.Close, () => { + this.#pages.delete(browsingContext); + }); - get connection(): BidiConnection { - return this.#connection; - } + // -- Target stuff starts here -- + const pageTarget = new BidiPageTarget(page); + const pageTargets = new Map(); + this.#targets.set(page, [pageTarget, pageTargets]); - override async newPage(): Promise<Page> { - const {result} = await this.#connection.send('browsingContext.create', { - type: Bidi.BrowsingContext.CreateType.Tab, + page.trustedEmitter.on(PageEvent.FrameAttached, frame => { + const bidiFrame = frame as BidiFrame; + const target = new BidiFrameTarget(bidiFrame); + pageTargets.set(bidiFrame, target); + this.trustedEmitter.emit(BrowserContextEvent.TargetCreated, target); + }); + page.trustedEmitter.on(PageEvent.FrameNavigated, frame => { + const bidiFrame = frame as BidiFrame; + const target = pageTargets.get(bidiFrame); + // If there is no target, then this is the page's frame. + if (target === undefined) { + this.trustedEmitter.emit(BrowserContextEvent.TargetChanged, pageTarget); + } else { + this.trustedEmitter.emit(BrowserContextEvent.TargetChanged, target); + } + }); + page.trustedEmitter.on(PageEvent.FrameDetached, frame => { + const bidiFrame = frame as BidiFrame; + const target = pageTargets.get(bidiFrame); + if (target === undefined) { + return; + } + pageTargets.delete(bidiFrame); + this.trustedEmitter.emit(BrowserContextEvent.TargetDestroyed, target); + }); + + page.trustedEmitter.on(PageEvent.WorkerCreated, worker => { + const bidiWorker = worker as BidiWebWorker; + const target = new BidiWorkerTarget(bidiWorker); + pageTargets.set(bidiWorker, target); + this.trustedEmitter.emit(BrowserContextEvent.TargetCreated, target); + }); + page.trustedEmitter.on(PageEvent.WorkerDestroyed, worker => { + const bidiWorker = worker as BidiWebWorker; + const target = pageTargets.get(bidiWorker); + if (target === undefined) { + return; + } + pageTargets.delete(worker); + this.trustedEmitter.emit(BrowserContextEvent.TargetDestroyed, target); }); - const target = this.#browser._getTargetById(result.context); - // TODO: once BiDi has some concept matching BrowserContext, the newly - // created contexts should get automatically assigned to the right - // BrowserContext. For now, we assume that only explicitly created pages go - // to the current BrowserContext. Otherwise, the contexts get assigned to - // the default BrowserContext by the Browser. - target._setBrowserContext(this); + page.trustedEmitter.on(PageEvent.Close, () => { + this.#targets.delete(page); + this.trustedEmitter.emit(BrowserContextEvent.TargetDestroyed, pageTarget); + }); + this.trustedEmitter.emit(BrowserContextEvent.TargetCreated, pageTarget); + // -- Target stuff ends here -- + + return page; + } + + override targets(): Target[] { + return [...this.#targets.values()].flatMap(([target, frames]) => { + return [target, ...frames.values()]; + }); + } - const page = await target.page(); + override async newPage(): Promise<Page> { + const context = await this.userContext.createBrowsingContext( + Bidi.BrowsingContext.CreateType.Tab + ); + const page = this.#pages.get(context)!; if (!page) { throw new Error('Page is not found'); } @@ -99,18 +184,8 @@ export class BidiBrowserContext extends BrowserContext { throw new Error('Default context cannot be closed!'); } - // TODO: Remove once we have adopted the new browsing contexts. - for (const target of this.targets()) { - const page = await target?.page(); - try { - await page?.close(); - } catch (error) { - debugError(error); - } - } - try { - await this.#userContext.remove(); + await this.userContext.remove(); } catch (error) { debugError(error); } @@ -121,25 +196,73 @@ export class BidiBrowserContext extends BrowserContext { } override async pages(): Promise<BidiPage[]> { - const results = await Promise.all( - [...this.targets()].map(t => { - return t.page(); - }) - ); - return results.filter((p): p is BidiPage => { - return p !== null; + return [...this.userContext.browsingContexts].map(context => { + return this.#pages.get(context)!; }); } override isIncognito(): boolean { - return this.#userContext.id !== UserContext.DEFAULT; + return this.userContext.id !== UserContext.DEFAULT; } - override overridePermissions(): never { - throw new UnsupportedOperation(); + override async overridePermissions( + origin: string, + permissions: Permission[] + ): Promise<void> { + const permissionsSet = new Set( + permissions.map(permission => { + const protocolPermission = + WEB_PERMISSION_TO_PROTOCOL_PERMISSION.get(permission); + if (!protocolPermission) { + throw new Error('Unknown permission: ' + permission); + } + return permission; + }) + ); + await Promise.all( + Array.from(WEB_PERMISSION_TO_PROTOCOL_PERMISSION.keys()).map( + permission => { + const result = this.userContext.setPermissions( + origin, + { + name: permission, + }, + permissionsSet.has(permission) + ? Bidi.Permissions.PermissionState.Granted + : Bidi.Permissions.PermissionState.Denied + ); + this.#overrides.push({origin, permission}); + // TODO: some permissions are outdated and setting them to denied does + // not work. + if (!permissionsSet.has(permission)) { + return result.catch(debugError); + } + return result; + } + ) + ); } - override clearPermissionOverrides(): never { - throw new UnsupportedOperation(); + override async clearPermissionOverrides(): Promise<void> { + const promises = this.#overrides.map(({permission, origin}) => { + return this.userContext + .setPermissions( + origin, + { + name: permission, + }, + Bidi.Permissions.PermissionState.Prompt + ) + .catch(debugError); + }); + this.#overrides = []; + await Promise.all(promises); + } + + override get id(): string | undefined { + if (this.userContext.id === UserContext.DEFAULT) { + return undefined; + } + return this.userContext.id; } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/BrowsingContext.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/BrowsingContext.ts deleted file mode 100644 index 0804628c06..0000000000 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/BrowsingContext.ts +++ /dev/null @@ -1,187 +0,0 @@ -import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; -import type ProtocolMapping from 'devtools-protocol/types/protocol-mapping.js'; - -import {CDPSession} from '../api/CDPSession.js'; -import type {Connection as CdpConnection} from '../cdp/Connection.js'; -import {TargetCloseError, UnsupportedOperation} from '../common/Errors.js'; -import type {EventType} from '../common/EventEmitter.js'; -import {debugError} from '../common/util.js'; -import {Deferred} from '../util/Deferred.js'; - -import type {BidiConnection} from './Connection.js'; -import {BidiRealm} from './Realm.js'; - -/** - * @internal - */ -export const cdpSessions = new Map<string, CdpSessionWrapper>(); - -/** - * @internal - */ -export class CdpSessionWrapper extends CDPSession { - #context: BrowsingContext; - #sessionId = Deferred.create<string>(); - #detached = false; - - constructor(context: BrowsingContext, sessionId?: string) { - super(); - this.#context = context; - if (!this.#context.supportsCdp()) { - return; - } - if (sessionId) { - this.#sessionId.resolve(sessionId); - cdpSessions.set(sessionId, this); - } else { - context.connection - .send('cdp.getSession', { - context: context.id, - }) - .then(session => { - this.#sessionId.resolve(session.result.session!); - cdpSessions.set(session.result.session!, this); - }) - .catch(err => { - this.#sessionId.reject(err); - }); - } - } - - override connection(): CdpConnection | undefined { - return undefined; - } - - override async send<T extends keyof ProtocolMapping.Commands>( - method: T, - ...paramArgs: ProtocolMapping.Commands[T]['paramsType'] - ): Promise<ProtocolMapping.Commands[T]['returnType']> { - if (!this.#context.supportsCdp()) { - throw new UnsupportedOperation( - 'CDP support is required for this feature. The current browser does not support CDP.' - ); - } - if (this.#detached) { - throw new TargetCloseError( - `Protocol error (${method}): Session closed. Most likely the page has been closed.` - ); - } - const session = await this.#sessionId.valueOrThrow(); - const {result} = await this.#context.connection.send('cdp.sendCommand', { - method: method, - params: paramArgs[0], - session, - }); - return result.result; - } - - override async detach(): Promise<void> { - cdpSessions.delete(this.id()); - if (!this.#detached && this.#context.supportsCdp()) { - await this.#context.cdpSession.send('Target.detachFromTarget', { - sessionId: this.id(), - }); - } - this.#detached = true; - } - - override id(): string { - const val = this.#sessionId.value(); - return val instanceof Error || val === undefined ? '' : val; - } -} - -/** - * Internal events that the BrowsingContext class emits. - * - * @internal - */ -// eslint-disable-next-line @typescript-eslint/no-namespace -export namespace BrowsingContextEvent { - /** - * Emitted on the top-level context, when a descendant context is created. - */ - export const Created = Symbol('BrowsingContext.created'); - /** - * Emitted on the top-level context, when a descendant context or the - * top-level context itself is destroyed. - */ - export const Destroyed = Symbol('BrowsingContext.destroyed'); -} - -/** - * @internal - */ -export interface BrowsingContextEvents extends Record<EventType, unknown> { - [BrowsingContextEvent.Created]: BrowsingContext; - [BrowsingContextEvent.Destroyed]: BrowsingContext; -} - -/** - * @internal - */ -export class BrowsingContext extends BidiRealm { - #id: string; - #url: string; - #cdpSession: CDPSession; - #parent?: string | null; - #browserName = ''; - - constructor( - connection: BidiConnection, - info: Bidi.BrowsingContext.Info, - browserName: string - ) { - super(connection); - this.#id = info.context; - this.#url = info.url; - this.#parent = info.parent; - this.#browserName = browserName; - this.#cdpSession = new CdpSessionWrapper(this, undefined); - - this.on('browsingContext.domContentLoaded', this.#updateUrl.bind(this)); - this.on('browsingContext.fragmentNavigated', this.#updateUrl.bind(this)); - this.on('browsingContext.load', this.#updateUrl.bind(this)); - } - - supportsCdp(): boolean { - return !this.#browserName.toLowerCase().includes('firefox'); - } - - #updateUrl(info: Bidi.BrowsingContext.NavigationInfo) { - this.#url = info.url; - } - - createRealmForSandbox(): BidiRealm { - return new BidiRealm(this.connection); - } - - get url(): string { - return this.#url; - } - - get id(): string { - return this.#id; - } - - get parent(): string | undefined | null { - return this.#parent; - } - - get cdpSession(): CDPSession { - return this.#cdpSession; - } - - async sendCdpCommand<T extends keyof ProtocolMapping.Commands>( - method: T, - ...paramArgs: ProtocolMapping.Commands[T]['paramsType'] - ): Promise<ProtocolMapping.Commands[T]['returnType']> { - return await this.#cdpSession.send(method, ...paramArgs); - } - - dispose(): void { - this.removeAllListeners(); - this.connection.unregisterBrowsingContexts(this.#id); - void this.#cdpSession.detach().catch(debugError); - } -} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/CDPSession.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/CDPSession.ts new file mode 100644 index 0000000000..1e0c503498 --- /dev/null +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/CDPSession.ts @@ -0,0 +1,103 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +import type ProtocolMapping from 'devtools-protocol/types/protocol-mapping.js'; + +import {CDPSession} from '../api/CDPSession.js'; +import type {Connection as CdpConnection} from '../cdp/Connection.js'; +import {TargetCloseError, UnsupportedOperation} from '../common/Errors.js'; +import {Deferred} from '../util/Deferred.js'; + +import type {BidiConnection} from './Connection.js'; +import type {BidiFrame} from './Frame.js'; + +/** + * @internal + */ +export class BidiCdpSession extends CDPSession { + static sessions = new Map<string, BidiCdpSession>(); + + #detached = false; + readonly #connection: BidiConnection | undefined = undefined; + readonly #sessionId = Deferred.create<string>(); + readonly frame: BidiFrame; + + constructor(frame: BidiFrame, sessionId?: string) { + super(); + this.frame = frame; + if (!this.frame.page().browser().cdpSupported) { + return; + } + + const connection = this.frame.page().browser().connection; + this.#connection = connection; + + if (sessionId) { + this.#sessionId.resolve(sessionId); + BidiCdpSession.sessions.set(sessionId, this); + } else { + (async () => { + try { + const session = await connection.send('cdp.getSession', { + context: frame._id, + }); + this.#sessionId.resolve(session.result.session!); + BidiCdpSession.sessions.set(session.result.session!, this); + } catch (error) { + this.#sessionId.reject(error as Error); + } + })(); + } + + // SAFETY: We never throw #sessionId. + BidiCdpSession.sessions.set(this.#sessionId.value() as string, this); + } + + override connection(): CdpConnection | undefined { + return undefined; + } + + override async send<T extends keyof ProtocolMapping.Commands>( + method: T, + params?: ProtocolMapping.Commands[T]['paramsType'][0] + ): Promise<ProtocolMapping.Commands[T]['returnType']> { + if (this.#connection === undefined) { + throw new UnsupportedOperation( + 'CDP support is required for this feature. The current browser does not support CDP.' + ); + } + if (this.#detached) { + throw new TargetCloseError( + `Protocol error (${method}): Session closed. Most likely the page has been closed.` + ); + } + const session = await this.#sessionId.valueOrThrow(); + const {result} = await this.#connection.send('cdp.sendCommand', { + method: method, + params: params, + session, + }); + return result.result; + } + + override async detach(): Promise<void> { + if (this.#connection === undefined || this.#detached) { + return; + } + try { + await this.frame.client.send('Target.detachFromTarget', { + sessionId: this.id(), + }); + } finally { + BidiCdpSession.sessions.delete(this.id()); + this.#detached = true; + } + } + + override id(): string { + const value = this.#sessionId.value(); + return typeof value === 'string' ? value : ''; + } +} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Connection.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Connection.ts index bce952ba39..dd688c309a 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Connection.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Connection.ts @@ -14,10 +14,10 @@ import {EventEmitter} from '../common/EventEmitter.js'; import {debugError} from '../common/util.js'; import {assert} from '../util/assert.js'; -import {cdpSessions, type BrowsingContext} from './BrowsingContext.js'; +import {BidiCdpSession} from './CDPSession.js'; import type { - BidiEvents, Commands as BidiCommands, + BidiEvents, Connection, } from './core/Connection.js'; @@ -36,6 +36,10 @@ export interface Commands extends BidiCommands { params: Bidi.Cdp.GetSessionParameters; returnType: Bidi.Cdp.GetSessionResult; }; + 'cdp.resolveRealm': { + params: Bidi.Cdp.ResolveRealmParameters; + returnType: Bidi.Cdp.ResolveRealmResult; + }; } /** @@ -51,7 +55,6 @@ export class BidiConnection #timeout? = 0; #closed = false; #callbacks = new CallbackRegistry(); - #browsingContexts = new Map<string, BrowsingContext>(); #emitters: Array<EventEmitter<any>> = []; constructor( @@ -137,12 +140,11 @@ export class BidiConnection return; case 'event': if (isCdpEvent(object)) { - cdpSessions + BidiCdpSession.sessions .get(object.params.session) ?.emit(object.params.event, object.params.params); return; } - this.#maybeEmitOnContext(object); // SAFETY: We know the method and parameter still match here. this.emit( object.method, @@ -163,52 +165,6 @@ export class BidiConnection debugError(object); } - #maybeEmitOnContext(event: Bidi.ChromiumBidi.Event) { - let context: BrowsingContext | undefined; - // Context specific events - if ('context' in event.params && event.params.context !== null) { - context = this.#browsingContexts.get(event.params.context); - // `log.entryAdded` specific context - } else if ( - 'source' in event.params && - event.params.source.context !== undefined - ) { - context = this.#browsingContexts.get(event.params.source.context); - } - context?.emit(event.method, event.params); - } - - registerBrowsingContexts(context: BrowsingContext): void { - this.#browsingContexts.set(context.id, context); - } - - getBrowsingContext(contextId: string): BrowsingContext { - const currentContext = this.#browsingContexts.get(contextId); - if (!currentContext) { - throw new Error(`BrowsingContext ${contextId} does not exist.`); - } - return currentContext; - } - - getTopLevelContext(contextId: string): BrowsingContext { - let currentContext = this.#browsingContexts.get(contextId); - if (!currentContext) { - throw new Error(`BrowsingContext ${contextId} does not exist.`); - } - while (currentContext.parent) { - contextId = currentContext.parent; - currentContext = this.#browsingContexts.get(contextId); - if (!currentContext) { - throw new Error(`BrowsingContext ${contextId} does not exist.`); - } - } - return currentContext; - } - - unregisterBrowsingContexts(id: string): void { - this.#browsingContexts.delete(id); - } - /** * Unbinds the connection, but keeps the transport open. Useful when the transport will * be reused by other connection e.g. with different protocol. @@ -223,7 +179,6 @@ export class BidiConnection this.#transport.onmessage = () => {}; this.#transport.onclose = () => {}; - this.#browsingContexts.clear(); this.#callbacks.clear(); } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Deserializer.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Deserializer.ts index 14b87d403b..20dc8d9fc9 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Deserializer.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Deserializer.ts @@ -12,40 +12,30 @@ import {debugError} from '../common/util.js'; * @internal */ export class BidiDeserializer { - static deserializeNumber(value: Bidi.Script.SpecialNumber | number): number { - switch (value) { - case '-0': - return -0; - case 'NaN': - return NaN; - case 'Infinity': - return Infinity; - case '-Infinity': - return -Infinity; - default: - return value; + static deserialize(result: Bidi.Script.RemoteValue): any { + if (!result) { + debugError('Service did not produce a result.'); + return undefined; } - } - static deserializeLocalValue(result: Bidi.Script.RemoteValue): unknown { switch (result.type) { case 'array': return result.value?.map(value => { - return BidiDeserializer.deserializeLocalValue(value); + return this.deserialize(value); }); case 'set': return result.value?.reduce((acc: Set<unknown>, value) => { - return acc.add(BidiDeserializer.deserializeLocalValue(value)); + return acc.add(this.deserialize(value)); }, new Set()); case 'object': return result.value?.reduce((acc: Record<any, unknown>, tuple) => { - const {key, value} = BidiDeserializer.deserializeTuple(tuple); + const {key, value} = this.#deserializeTuple(tuple); acc[key as any] = value; return acc; }, {}); case 'map': return result.value?.reduce((acc: Map<unknown, unknown>, tuple) => { - const {key, value} = BidiDeserializer.deserializeTuple(tuple); + const {key, value} = this.#deserializeTuple(tuple); return acc.set(key, value); }, new Map()); case 'promise': @@ -59,7 +49,7 @@ export class BidiDeserializer { case 'null': return null; case 'number': - return BidiDeserializer.deserializeNumber(result.value); + return this.#deserializeNumber(result.value); case 'bigint': return BigInt(result.value); case 'boolean': @@ -72,25 +62,31 @@ export class BidiDeserializer { return undefined; } - static deserializeTuple([serializedKey, serializedValue]: [ + static #deserializeNumber(value: Bidi.Script.SpecialNumber | number): number { + switch (value) { + case '-0': + return -0; + case 'NaN': + return NaN; + case 'Infinity': + return Infinity; + case '-Infinity': + return -Infinity; + default: + return value; + } + } + + static #deserializeTuple([serializedKey, serializedValue]: [ Bidi.Script.RemoteValue | string, Bidi.Script.RemoteValue, ]): {key: unknown; value: unknown} { const key = typeof serializedKey === 'string' ? serializedKey - : BidiDeserializer.deserializeLocalValue(serializedKey); - const value = BidiDeserializer.deserializeLocalValue(serializedValue); + : this.deserialize(serializedKey); + const value = this.deserialize(serializedValue); return {key, value}; } - - static deserialize(result: Bidi.Script.RemoteValue): any { - if (!result) { - debugError('Service did not produce a result.'); - return undefined; - } - - return BidiDeserializer.deserializeLocalValue(result); - } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Dialog.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Dialog.ts index ce22223461..1774a29f6b 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Dialog.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Dialog.ts @@ -4,40 +4,26 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; - import {Dialog} from '../api/Dialog.js'; -import type {BrowsingContext} from './BrowsingContext.js'; +import type {UserPrompt} from './core/UserPrompt.js'; -/** - * @internal - */ export class BidiDialog extends Dialog { - #context: BrowsingContext; + static from(prompt: UserPrompt): BidiDialog { + return new BidiDialog(prompt); + } - /** - * @internal - */ - constructor( - context: BrowsingContext, - type: Bidi.BrowsingContext.UserPromptOpenedParameters['type'], - message: string, - defaultValue?: string - ) { - super(type, message, defaultValue); - this.#context = context; + #prompt: UserPrompt; + private constructor(prompt: UserPrompt) { + super(prompt.info.type, prompt.info.message, prompt.info.defaultValue); + this.#prompt = prompt; } - /** - * @internal - */ override async handle(options: { accept: boolean; text?: string; }): Promise<void> { - await this.#context.connection.send('browsingContext.handleUserPrompt', { - context: this.#context.id, + await this.#prompt.handle({ accept: options.accept, userText: options.text, }); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ElementHandle.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ElementHandle.ts index fd886e8c26..4263697671 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ElementHandle.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ElementHandle.ts @@ -6,14 +6,12 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; -import {type AutofillData, ElementHandle} from '../api/ElementHandle.js'; -import {UnsupportedOperation} from '../common/Errors.js'; +import {ElementHandle, type AutofillData} from '../api/ElementHandle.js'; import {throwIfDisposed} from '../util/decorators.js'; import type {BidiFrame} from './Frame.js'; import {BidiJSHandle} from './JSHandle.js'; -import type {BidiRealm} from './Realm.js'; -import type {Sandbox} from './Sandbox.js'; +import type {BidiFrameRealm} from './Realm.js'; /** * @internal @@ -21,28 +19,28 @@ import type {Sandbox} from './Sandbox.js'; export class BidiElementHandle< ElementType extends Node = Element, > extends ElementHandle<ElementType> { + static from<ElementType extends Node = Element>( + value: Bidi.Script.RemoteValue, + realm: BidiFrameRealm + ): BidiElementHandle<ElementType> { + return new BidiElementHandle(value, realm); + } + declare handle: BidiJSHandle<ElementType>; - constructor(sandbox: Sandbox, remoteValue: Bidi.Script.RemoteValue) { - super(new BidiJSHandle(sandbox, remoteValue)); + constructor(value: Bidi.Script.RemoteValue, realm: BidiFrameRealm) { + super(BidiJSHandle.from(value, realm)); } - override get realm(): Sandbox { - return this.handle.realm; + override get realm(): BidiFrameRealm { + // SAFETY: See the super call in the constructor. + return this.handle.realm as BidiFrameRealm; } override get frame(): BidiFrame { return this.realm.environment; } - context(): BidiRealm { - return this.handle.context(); - } - - get isPrimitiveValue(): boolean { - return this.handle.isPrimitiveValue; - } - remoteValue(): Bidi.Script.RemoteValue { return this.handle.remoteValue(); } @@ -69,19 +67,53 @@ export class BidiElementHandle< @ElementHandle.bindIsolatedHandle override async contentFrame(): Promise<BidiFrame | null> { using handle = (await this.evaluateHandle(element => { - if (element instanceof HTMLIFrameElement) { + if ( + element instanceof HTMLIFrameElement || + element instanceof HTMLFrameElement + ) { return element.contentWindow; } return; })) as BidiJSHandle; const value = handle.remoteValue(); if (value.type === 'window') { - return this.frame.page().frame(value.value.context); + return ( + this.frame + .page() + .frames() + .find(frame => { + return frame._id === value.value.context; + }) ?? null + ); } return null; } - override uploadFile(this: ElementHandle<HTMLInputElement>): never { - throw new UnsupportedOperation(); + override async uploadFile( + this: BidiElementHandle<HTMLInputElement>, + ...files: string[] + ): Promise<void> { + // Locate all files and confirm that they exist. + // eslint-disable-next-line @typescript-eslint/consistent-type-imports + let path: typeof import('path'); + try { + path = await import('path'); + } catch (error) { + if (error instanceof TypeError) { + throw new Error( + `JSHandle#uploadFile can only be used in Node-like environments.` + ); + } + throw error; + } + + files = files.map(file => { + if (path.win32.isAbsolute(file) || path.posix.isAbsolute(file)) { + return file; + } else { + return path.resolve(file); + } + }); + await this.frame.setFiles(this, files); } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/EmulationManager.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/EmulationManager.ts deleted file mode 100644 index de95695785..0000000000 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/EmulationManager.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @license - * Copyright 2023 Google Inc. - * SPDX-License-Identifier: Apache-2.0 - */ -import type {Viewport} from '../common/Viewport.js'; - -import type {BrowsingContext} from './BrowsingContext.js'; - -/** - * @internal - */ -export class EmulationManager { - #browsingContext: BrowsingContext; - - constructor(browsingContext: BrowsingContext) { - this.#browsingContext = browsingContext; - } - - async emulateViewport(viewport: Viewport): Promise<void> { - await this.#browsingContext.connection.send('browsingContext.setViewport', { - context: this.#browsingContext.id, - viewport: - viewport.width && viewport.height - ? { - width: viewport.width, - height: viewport.height, - } - : null, - devicePixelRatio: viewport.deviceScaleFactor - ? viewport.deviceScaleFactor - : null, - }); - } -} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ExposedFunction.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ExposedFunction.ts index 62c6b5e37e..f6e1304a55 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ExposedFunction.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ExposedFunction.ts @@ -6,97 +6,91 @@ import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; +import {EventEmitter} from '../common/EventEmitter.js'; import type {Awaitable, FlattenHandle} from '../common/types.js'; import {debugError} from '../common/util.js'; -import {assert} from '../util/assert.js'; -import {Deferred} from '../util/Deferred.js'; +import {DisposableStack} from '../util/disposable.js'; import {interpolateFunction, stringifyFunction} from '../util/Function.js'; -import type {BidiConnection} from './Connection.js'; -import {BidiDeserializer} from './Deserializer.js'; +import type {Connection} from './core/Connection.js'; +import {BidiElementHandle} from './ElementHandle.js'; import type {BidiFrame} from './Frame.js'; -import {BidiSerializer} from './Serializer.js'; - -type SendArgsChannel<Args> = (value: [id: number, args: Args]) => void; -type SendResolveChannel<Ret> = ( - value: [id: number, resolve: (ret: FlattenHandle<Awaited<Ret>>) => void] -) => void; -type SendRejectChannel = ( - value: [id: number, reject: (error: unknown) => void] +import {BidiJSHandle} from './JSHandle.js'; + +type CallbackChannel<Args, Ret> = ( + value: [ + resolve: (ret: FlattenHandle<Awaited<Ret>>) => void, + reject: (error: unknown) => void, + args: Args, + ] ) => void; -interface RemotePromiseCallbacks { - resolve: Deferred<Bidi.Script.RemoteValue>; - reject: Deferred<Bidi.Script.RemoteValue>; -} - /** * @internal */ export class ExposeableFunction<Args extends unknown[], Ret> { + static async from<Args extends unknown[], Ret>( + frame: BidiFrame, + name: string, + apply: (...args: Args) => Awaitable<Ret>, + isolate = false + ): Promise<ExposeableFunction<Args, Ret>> { + const func = new ExposeableFunction(frame, name, apply, isolate); + await func.#initialize(); + return func; + } + readonly #frame; readonly name; readonly #apply; + readonly #isolate; - readonly #channels; - readonly #callerInfos = new Map< - string, - Map<number, RemotePromiseCallbacks> - >(); + readonly #channel; - #preloadScriptId?: Bidi.Script.PreloadScript; + #scripts: Array<[BidiFrame, Bidi.Script.PreloadScript]> = []; + #disposables = new DisposableStack(); constructor( frame: BidiFrame, name: string, - apply: (...args: Args) => Awaitable<Ret> + apply: (...args: Args) => Awaitable<Ret>, + isolate = false ) { this.#frame = frame; this.name = name; this.#apply = apply; + this.#isolate = isolate; - this.#channels = { - args: `__puppeteer__${this.#frame._id}_page_exposeFunction_${this.name}_args`, - resolve: `__puppeteer__${this.#frame._id}_page_exposeFunction_${this.name}_resolve`, - reject: `__puppeteer__${this.#frame._id}_page_exposeFunction_${this.name}_reject`, - }; + this.#channel = `__puppeteer__${this.#frame._id}_page_exposeFunction_${this.name}`; } - async expose(): Promise<void> { + async #initialize() { const connection = this.#connection; - const channelArguments = this.#channelArguments; + const channel = { + type: 'channel' as const, + value: { + channel: this.#channel, + ownership: Bidi.Script.ResultOwnership.Root, + }, + }; - // TODO(jrandolf): Implement cleanup with removePreloadScript. - connection.on( - Bidi.ChromiumBidi.Script.EventNames.Message, - this.#handleArgumentsMessage + const connectionEmitter = this.#disposables.use( + new EventEmitter(connection) ); - connection.on( + connectionEmitter.on( Bidi.ChromiumBidi.Script.EventNames.Message, - this.#handleResolveMessage - ); - connection.on( - Bidi.ChromiumBidi.Script.EventNames.Message, - this.#handleRejectMessage + this.#handleMessage ); const functionDeclaration = stringifyFunction( interpolateFunction( - ( - sendArgs: SendArgsChannel<Args>, - sendResolve: SendResolveChannel<Ret>, - sendReject: SendRejectChannel - ) => { - let id = 0; + (callback: CallbackChannel<Args, Ret>) => { Object.assign(globalThis, { [PLACEHOLDER('name') as string]: function (...args: Args) { return new Promise<FlattenHandle<Awaited<Ret>>>( (resolve, reject) => { - sendArgs([id, args]); - sendResolve([id, resolve]); - sendReject([id, reject]); - ++id; + callback([resolve, reject, args]); } ); }, @@ -106,179 +100,133 @@ export class ExposeableFunction<Args extends unknown[], Ret> { ) ); - const {result} = await connection.send('script.addPreloadScript', { - functionDeclaration, - arguments: channelArguments, - contexts: [this.#frame.page().mainFrame()._id], - }); - this.#preloadScriptId = result.script; + const frames = [this.#frame]; + for (const frame of frames) { + frames.push(...frame.childFrames()); + } await Promise.all( - this.#frame - .page() - .frames() - .map(async frame => { - return await connection.send('script.callFunction', { - functionDeclaration, - arguments: channelArguments, - awaitPromise: false, - target: frame.mainRealm().realm.target, - }); - }) + frames.map(async frame => { + const realm = this.#isolate ? frame.isolatedRealm() : frame.mainRealm(); + try { + const [script] = await Promise.all([ + frame.browsingContext.addPreloadScript(functionDeclaration, { + arguments: [channel], + sandbox: realm.sandbox, + }), + realm.realm.callFunction(functionDeclaration, false, { + arguments: [channel], + }), + ]); + this.#scripts.push([frame, script]); + } catch (error) { + // If it errors, the frame probably doesn't support call function. We + // fail gracefully. + debugError(error); + } + }) ); } - #handleArgumentsMessage = async (params: Bidi.Script.MessageParameters) => { - if (params.channel !== this.#channels.args) { + get #connection(): Connection { + return this.#frame.page().browser().connection; + } + + #handleMessage = async (params: Bidi.Script.MessageParameters) => { + if (params.channel !== this.#channel) { return; } - const connection = this.#connection; - const {callbacks, remoteValue} = this.#getCallbacksAndRemoteValue(params); - const args = remoteValue.value?.[1]; - assert(args); + const realm = this.#getRealm(params.source); + if (!realm) { + // Unrelated message. + return; + } + + using dataHandle = BidiJSHandle.from< + [ + resolve: (ret: FlattenHandle<Awaited<Ret>>) => void, + reject: (error: unknown) => void, + args: Args, + ] + >(params.data, realm); + + using argsHandle = await dataHandle.evaluateHandle(([, , args]) => { + return args; + }); + + using stack = new DisposableStack(); + const args = []; + for (const [index, handle] of await argsHandle.getProperties()) { + stack.use(handle); + + // Element handles are passed as is. + if (handle instanceof BidiElementHandle) { + args[+index] = handle; + stack.use(handle); + continue; + } + + // Everything else is passed as the JS value. + args[+index] = handle.jsonValue(); + } + + let result; try { - const result = await this.#apply(...BidiDeserializer.deserialize(args)); - await connection.send('script.callFunction', { - functionDeclaration: stringifyFunction(([_, resolve]: any, result) => { - resolve(result); - }), - arguments: [ - (await callbacks.resolve.valueOrThrow()) as Bidi.Script.LocalValue, - BidiSerializer.serializeRemoteValue(result), - ], - awaitPromise: false, - target: { - realm: params.source.realm, - }, - }); + result = await this.#apply(...((await Promise.all(args)) as Args)); } catch (error) { try { if (error instanceof Error) { - await connection.send('script.callFunction', { - functionDeclaration: stringifyFunction( - ( - [_, reject]: [unknown, (error: Error) => void], - name: string, - message: string, - stack?: string - ) => { - const error = new Error(message); - error.name = name; - if (stack) { - error.stack = stack; - } - reject(error); + await dataHandle.evaluate( + ([, reject], name, message, stack) => { + const error = new Error(message); + error.name = name; + if (stack) { + error.stack = stack; } - ), - arguments: [ - (await callbacks.reject.valueOrThrow()) as Bidi.Script.LocalValue, - BidiSerializer.serializeRemoteValue(error.name), - BidiSerializer.serializeRemoteValue(error.message), - BidiSerializer.serializeRemoteValue(error.stack), - ], - awaitPromise: false, - target: { - realm: params.source.realm, + reject(error); }, - }); + error.name, + error.message, + error.stack + ); } else { - await connection.send('script.callFunction', { - functionDeclaration: stringifyFunction( - ( - [_, reject]: [unknown, (error: unknown) => void], - error: unknown - ) => { - reject(error); - } - ), - arguments: [ - (await callbacks.reject.valueOrThrow()) as Bidi.Script.LocalValue, - BidiSerializer.serializeRemoteValue(error), - ], - awaitPromise: false, - target: { - realm: params.source.realm, - }, - }); + await dataHandle.evaluate(([, reject], error) => { + reject(error); + }, error); } } catch (error) { debugError(error); } - } - }; - - get #connection(): BidiConnection { - return this.#frame.context().connection; - } - - get #channelArguments() { - return [ - { - type: 'channel' as const, - value: { - channel: this.#channels.args, - ownership: Bidi.Script.ResultOwnership.Root, - }, - }, - { - type: 'channel' as const, - value: { - channel: this.#channels.resolve, - ownership: Bidi.Script.ResultOwnership.Root, - }, - }, - { - type: 'channel' as const, - value: { - channel: this.#channels.reject, - ownership: Bidi.Script.ResultOwnership.Root, - }, - }, - ]; - } - - #handleResolveMessage = (params: Bidi.Script.MessageParameters) => { - if (params.channel !== this.#channels.resolve) { return; } - const {callbacks, remoteValue} = this.#getCallbacksAndRemoteValue(params); - callbacks.resolve.resolve(remoteValue); - }; - #handleRejectMessage = (params: Bidi.Script.MessageParameters) => { - if (params.channel !== this.#channels.reject) { - return; + try { + await dataHandle.evaluate(([resolve], result) => { + resolve(result); + }, result); + } catch (error) { + debugError(error); } - const {callbacks, remoteValue} = this.#getCallbacksAndRemoteValue(params); - callbacks.reject.resolve(remoteValue); }; - #getCallbacksAndRemoteValue(params: Bidi.Script.MessageParameters) { - const {data, source} = params; - assert(data.type === 'array'); - assert(data.value); - - const callerIdRemote = data.value[0]; - assert(callerIdRemote); - assert(callerIdRemote.type === 'number'); - assert(typeof callerIdRemote.value === 'number'); - - let bindingMap = this.#callerInfos.get(source.realm); - if (!bindingMap) { - bindingMap = new Map(); - this.#callerInfos.set(source.realm, bindingMap); + #getRealm(source: Bidi.Script.Source) { + const frame = this.#findFrame(source.context as string); + if (!frame) { + // Unrelated message. + return; } + return frame.realm(source.realm); + } - const callerId = callerIdRemote.value; - let callbacks = bindingMap.get(callerId); - if (!callbacks) { - callbacks = { - resolve: new Deferred(), - reject: new Deferred(), - }; - bindingMap.set(callerId, callbacks); + #findFrame(id: string) { + const frames = [this.#frame]; + for (const frame of frames) { + if (frame._id === id) { + return frame; + } + frames.push(...frame.childFrames()); } - return {callbacks, remoteValue: data}; + return; } [Symbol.dispose](): void { @@ -286,10 +234,21 @@ export class ExposeableFunction<Args extends unknown[], Ret> { } async [Symbol.asyncDispose](): Promise<void> { - if (this.#preloadScriptId) { - await this.#connection.send('script.removePreloadScript', { - script: this.#preloadScriptId, - }); - } + this.#disposables.dispose(); + await Promise.all( + this.#scripts.map(async ([frame, script]) => { + const realm = this.#isolate ? frame.isolatedRealm() : frame.mainRealm(); + try { + await Promise.all([ + realm.evaluate(name => { + delete (globalThis as any)[name]; + }, this.name), + frame.browsingContext.removePreloadScript(script), + ]); + } catch (error) { + debugError(error); + } + }) + ); } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Frame.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Frame.ts index 1638c2cbdf..f2bfd5f64e 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Frame.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Frame.ts @@ -6,15 +6,18 @@ import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; +import type {Observable} from '../../third_party/rxjs/rxjs.js'; import { + combineLatest, + defer, + delayWhen, + filter, first, firstValueFrom, - forkJoin, - from, map, - merge, + of, raceWith, - zip, + switchMap, } from '../../third_party/rxjs/rxjs.js'; import type {CDPSession} from '../api/CDPSession.js'; import type {ElementHandle} from '../api/ElementHandle.js'; @@ -25,85 +28,228 @@ import { type WaitForOptions, } from '../api/Frame.js'; import type {WaitForSelectorOptions} from '../api/Page.js'; -import {UnsupportedOperation} from '../common/Errors.js'; +import {PageEvent} from '../api/Page.js'; +import { + ConsoleMessage, + type ConsoleMessageLocation, +} from '../common/ConsoleMessage.js'; +import {TargetCloseError, UnsupportedOperation} from '../common/Errors.js'; import type {TimeoutSettings} from '../common/TimeoutSettings.js'; import type {Awaitable, NodeFor} from '../common/types.js'; -import { - fromEmitterEvent, - NETWORK_IDLE_TIME, - timeout, - UTILITY_WORLD_NAME, -} from '../common/util.js'; -import {Deferred} from '../util/Deferred.js'; -import {disposeSymbol} from '../util/disposable.js'; - -import type {BrowsingContext} from './BrowsingContext.js'; +import {debugError, fromEmitterEvent, timeout} from '../common/util.js'; + +import {BidiCdpSession} from './CDPSession.js'; +import type {BrowsingContext} from './core/BrowsingContext.js'; +import type {Navigation} from './core/Navigation.js'; +import type {Request} from './core/Request.js'; +import {BidiDeserializer} from './Deserializer.js'; +import {BidiDialog} from './Dialog.js'; +import type {BidiElementHandle} from './ElementHandle.js'; import {ExposeableFunction} from './ExposedFunction.js'; +import {BidiHTTPRequest, requests} from './HTTPRequest.js'; import type {BidiHTTPResponse} from './HTTPResponse.js'; -import { - getBiDiLifecycleEvent, - getBiDiReadinessState, - rewriteNavigationError, -} from './lifecycle.js'; +import {BidiJSHandle} from './JSHandle.js'; import type {BidiPage} from './Page.js'; -import { - MAIN_SANDBOX, - PUPPETEER_SANDBOX, - Sandbox, - type SandboxChart, -} from './Sandbox.js'; +import type {BidiRealm} from './Realm.js'; +import {BidiFrameRealm} from './Realm.js'; +import {rewriteNavigationError} from './util.js'; +import {BidiWebWorker} from './WebWorker.js'; -/** - * Puppeteer's Frame class could be viewed as a BiDi BrowsingContext implementation - * @internal - */ export class BidiFrame extends Frame { - #page: BidiPage; - #context: BrowsingContext; - #timeoutSettings: TimeoutSettings; - #abortDeferred = Deferred.create<never>(); - #disposed = false; - sandboxes: SandboxChart; - override _id: string; - - constructor( - page: BidiPage, - context: BrowsingContext, - timeoutSettings: TimeoutSettings, - parentId?: string | null + static from( + parent: BidiPage | BidiFrame, + browsingContext: BrowsingContext + ): BidiFrame { + const frame = new BidiFrame(parent, browsingContext); + frame.#initialize(); + return frame; + } + + readonly #parent: BidiPage | BidiFrame; + readonly browsingContext: BrowsingContext; + readonly #frames = new WeakMap<BrowsingContext, BidiFrame>(); + readonly realms: {default: BidiFrameRealm; internal: BidiFrameRealm}; + + override readonly _id: string; + override readonly client: BidiCdpSession; + + private constructor( + parent: BidiPage | BidiFrame, + browsingContext: BrowsingContext ) { super(); - this.#page = page; - this.#context = context; - this.#timeoutSettings = timeoutSettings; - this._id = this.#context.id; - this._parentId = parentId ?? undefined; - - this.sandboxes = { - [MAIN_SANDBOX]: new Sandbox(undefined, this, context, timeoutSettings), - [PUPPETEER_SANDBOX]: new Sandbox( - UTILITY_WORLD_NAME, - this, - context.createRealmForSandbox(), - timeoutSettings + this.#parent = parent; + this.browsingContext = browsingContext; + + this._id = browsingContext.id; + this.client = new BidiCdpSession(this); + this.realms = { + default: BidiFrameRealm.from(this.browsingContext.defaultRealm, this), + internal: BidiFrameRealm.from( + this.browsingContext.createWindowRealm( + `__puppeteer_internal_${Math.ceil(Math.random() * 10000)}` + ), + this ), }; } - override get client(): CDPSession { - return this.context().cdpSession; + #initialize(): void { + for (const browsingContext of this.browsingContext.children) { + this.#createFrameTarget(browsingContext); + } + + this.browsingContext.on('browsingcontext', ({browsingContext}) => { + this.#createFrameTarget(browsingContext); + }); + this.browsingContext.on('closed', () => { + for (const session of BidiCdpSession.sessions.values()) { + if (session.frame === this) { + void session.detach().catch(debugError); + } + } + this.page().trustedEmitter.emit(PageEvent.FrameDetached, this); + }); + + this.browsingContext.on('request', ({request}) => { + const httpRequest = BidiHTTPRequest.from(request, this); + request.once('success', () => { + // SAFETY: BidiHTTPRequest will create this before here. + this.page().trustedEmitter.emit(PageEvent.RequestFinished, httpRequest); + }); + + request.once('error', () => { + this.page().trustedEmitter.emit(PageEvent.RequestFailed, httpRequest); + }); + }); + + this.browsingContext.on('navigation', ({navigation}) => { + navigation.once('fragment', () => { + this.page().trustedEmitter.emit(PageEvent.FrameNavigated, this); + }); + }); + this.browsingContext.on('load', () => { + this.page().trustedEmitter.emit(PageEvent.Load, undefined); + }); + this.browsingContext.on('DOMContentLoaded', () => { + this._hasStartedLoading = true; + this.page().trustedEmitter.emit(PageEvent.DOMContentLoaded, undefined); + this.page().trustedEmitter.emit(PageEvent.FrameNavigated, this); + }); + + this.browsingContext.on('userprompt', ({userPrompt}) => { + this.page().trustedEmitter.emit( + PageEvent.Dialog, + BidiDialog.from(userPrompt) + ); + }); + + this.browsingContext.on('log', ({entry}) => { + if (this._id !== entry.source.context) { + return; + } + if (isConsoleLogEntry(entry)) { + const args = entry.args.map(arg => { + return this.mainRealm().createHandle(arg); + }); + + const text = args + .reduce((value, arg) => { + const parsedValue = + arg instanceof BidiJSHandle && arg.isPrimitiveValue + ? BidiDeserializer.deserialize(arg.remoteValue()) + : arg.toString(); + return `${value} ${parsedValue}`; + }, '') + .slice(1); + + this.page().trustedEmitter.emit( + PageEvent.Console, + new ConsoleMessage( + entry.method as any, + text, + args, + getStackTraceLocations(entry.stackTrace) + ) + ); + } else if (isJavaScriptLogEntry(entry)) { + const error = new Error(entry.text ?? ''); + + const messageHeight = error.message.split('\n').length; + const messageLines = error.stack!.split('\n').splice(0, messageHeight); + + const stackLines = []; + if (entry.stackTrace) { + for (const frame of entry.stackTrace.callFrames) { + // Note we need to add `1` because the values are 0-indexed. + stackLines.push( + ` at ${frame.functionName || '<anonymous>'} (${frame.url}:${ + frame.lineNumber + 1 + }:${frame.columnNumber + 1})` + ); + if (stackLines.length >= Error.stackTraceLimit) { + break; + } + } + } + + error.stack = [...messageLines, ...stackLines].join('\n'); + this.page().trustedEmitter.emit(PageEvent.PageError, error); + } else { + debugError( + `Unhandled LogEntry with type "${entry.type}", text "${entry.text}" and level "${entry.level}"` + ); + } + }); + + this.browsingContext.on('worker', ({realm}) => { + const worker = BidiWebWorker.from(this, realm); + realm.on('destroyed', () => { + this.page().trustedEmitter.emit(PageEvent.WorkerDestroyed, worker); + }); + this.page().trustedEmitter.emit(PageEvent.WorkerCreated, worker); + }); + } + + #createFrameTarget(browsingContext: BrowsingContext) { + const frame = BidiFrame.from(this, browsingContext); + this.#frames.set(browsingContext, frame); + this.page().trustedEmitter.emit(PageEvent.FrameAttached, frame); + + browsingContext.on('closed', () => { + this.#frames.delete(browsingContext); + }); + + return frame; + } + + get timeoutSettings(): TimeoutSettings { + return this.page()._timeoutSettings; } - override mainRealm(): Sandbox { - return this.sandboxes[MAIN_SANDBOX]; + override mainRealm(): BidiFrameRealm { + return this.realms.default; } - override isolatedRealm(): Sandbox { - return this.sandboxes[PUPPETEER_SANDBOX]; + override isolatedRealm(): BidiFrameRealm { + return this.realms.internal; + } + + realm(id: string): BidiRealm | undefined { + for (const realm of Object.values(this.realms)) { + if (realm.realm.id === id) { + return realm; + } + } + return; } override page(): BidiPage { - return this.#page; + let parent = this.#parent; + while (parent instanceof BidiFrame) { + parent = parent.#parent; + } + return parent; } override isOOPFrame(): never { @@ -111,15 +257,36 @@ export class BidiFrame extends Frame { } override url(): string { - return this.#context.url; + return this.browsingContext.url; } override parentFrame(): BidiFrame | null { - return this.#page.frame(this._parentId ?? ''); + if (this.#parent instanceof BidiFrame) { + return this.#parent; + } + return null; } override childFrames(): BidiFrame[] { - return this.#page.childFrames(this.#context.id); + return [...this.browsingContext.children].map(child => { + return this.#frames.get(child)!; + }); + } + + #detached$() { + return defer(() => { + if (this.detached) { + return of(this as Frame); + } + return fromEmitterEvent( + this.page().trustedEmitter, + PageEvent.FrameDetached + ).pipe( + filter(detachedFrame => { + return detachedFrame === this; + }) + ); + }); } @throwIfDetached @@ -127,40 +294,23 @@ export class BidiFrame extends Frame { url: string, options: GoToOptions = {} ): Promise<BidiHTTPResponse | null> { - const { - waitUntil = 'load', - timeout: ms = this.#timeoutSettings.navigationTimeout(), - } = options; - - const [readiness, networkIdle] = getBiDiReadinessState(waitUntil); - - const result$ = zip( - from( - this.#context.connection.send('browsingContext.navigate', { - context: this.#context.id, - url, - wait: readiness, - }) + const [response] = await Promise.all([ + this.waitForNavigation(options), + // Some implementations currently only report errors when the + // readiness=interactive. + // + // Related: https://bugzilla.mozilla.org/show_bug.cgi?id=1846601 + this.browsingContext.navigate( + url, + Bidi.BrowsingContext.ReadinessState.Interactive ), - ...(networkIdle !== null - ? [ - this.#page.waitForNetworkIdle$({ - timeout: ms, - concurrency: networkIdle === 'networkidle2' ? 2 : 0, - idleTime: NETWORK_IDLE_TIME, - }), - ] - : []) - ).pipe( - map(([{result}]) => { - return result; - }), - raceWith(timeout(ms), from(this.#abortDeferred.valueOrThrow())), - rewriteNavigationError(url, ms) + ]).catch( + rewriteNavigationError( + url, + options.timeout ?? this.timeoutSettings.navigationTimeout() + ) ); - - const result = await firstValueFrom(result$); - return this.#page.getNavigationResponse(result.navigation); + return response; } @throwIfDetached @@ -168,95 +318,105 @@ export class BidiFrame extends Frame { html: string, options: WaitForOptions = {} ): Promise<void> { - const { - waitUntil = 'load', - timeout: ms = this.#timeoutSettings.navigationTimeout(), - } = options; - - const [waitEvent, networkIdle] = getBiDiLifecycleEvent(waitUntil); - - const result$ = zip( - forkJoin([ - fromEmitterEvent(this.#context, waitEvent).pipe(first()), - from(this.setFrameContent(html)), - ]).pipe( - map(() => { - return null; - }) + await Promise.all([ + this.setFrameContent(html), + firstValueFrom( + combineLatest([ + this.#waitForLoad$(options), + this.#waitForNetworkIdle$(options), + ]) ), - ...(networkIdle !== null - ? [ - this.#page.waitForNetworkIdle$({ - timeout: ms, - concurrency: networkIdle === 'networkidle2' ? 2 : 0, - idleTime: NETWORK_IDLE_TIME, - }), - ] - : []) - ).pipe( - raceWith(timeout(ms), from(this.#abortDeferred.valueOrThrow())), - rewriteNavigationError('setContent', ms) - ); - - await firstValueFrom(result$); - } - - context(): BrowsingContext { - return this.#context; + ]); } @throwIfDetached override async waitForNavigation( options: WaitForOptions = {} ): Promise<BidiHTTPResponse | null> { - const { - waitUntil = 'load', - timeout: ms = this.#timeoutSettings.navigationTimeout(), - } = options; - - const [waitUntilEvent, networkIdle] = getBiDiLifecycleEvent(waitUntil); - - const navigation$ = merge( - forkJoin([ - fromEmitterEvent( - this.#context, - Bidi.ChromiumBidi.BrowsingContext.EventNames.NavigationStarted - ).pipe(first()), - fromEmitterEvent(this.#context, waitUntilEvent).pipe(first()), - ]), - fromEmitterEvent( - this.#context, - Bidi.ChromiumBidi.BrowsingContext.EventNames.FragmentNavigated + const {timeout: ms = this.timeoutSettings.navigationTimeout()} = options; + + const frames = this.childFrames().map(frame => { + return frame.#detached$(); + }); + return await firstValueFrom( + combineLatest([ + fromEmitterEvent(this.browsingContext, 'navigation').pipe( + switchMap(({navigation}) => { + return this.#waitForLoad$(options).pipe( + delayWhen(() => { + if (frames.length === 0) { + return of(undefined); + } + return combineLatest(frames); + }), + raceWith( + fromEmitterEvent(navigation, 'fragment'), + fromEmitterEvent(navigation, 'failed').pipe( + map(({url}) => { + throw new Error(`Navigation failed: ${url}`); + }) + ), + fromEmitterEvent(navigation, 'aborted').pipe( + map(({url}) => { + throw new Error(`Navigation aborted: ${url}`); + }) + ) + ), + switchMap(() => { + if (navigation.request) { + function requestFinished$( + request: Request + ): Observable<Navigation> { + // Reduces flakiness if the response events arrive after + // the load event. + // Usually, the response or error is already there at this point. + if (request.response || request.error) { + return of(navigation); + } + if (request.redirect) { + return requestFinished$(request.redirect); + } + return fromEmitterEvent(request, 'success') + .pipe( + raceWith(fromEmitterEvent(request, 'error')), + raceWith(fromEmitterEvent(request, 'redirect')) + ) + .pipe( + switchMap(() => { + return requestFinished$(request); + }) + ); + } + return requestFinished$(navigation.request); + } + return of(navigation); + }) + ); + }) + ), + this.#waitForNetworkIdle$(options), + ]).pipe( + map(([navigation]) => { + const request = navigation.request; + if (!request) { + return null; + } + const httpRequest = requests.get(request)!; + const lastRedirect = httpRequest.redirectChain().at(-1); + return ( + lastRedirect !== undefined ? lastRedirect : httpRequest + ).response(); + }), + raceWith( + timeout(ms), + this.#detached$().pipe( + map(() => { + throw new TargetCloseError('Frame detached.'); + }) + ) + ) ) - ).pipe( - map(result => { - if (Array.isArray(result)) { - return {result: result[1]}; - } - return {result}; - }) ); - - const result$ = zip( - navigation$, - ...(networkIdle !== null - ? [ - this.#page.waitForNetworkIdle$({ - timeout: ms, - concurrency: networkIdle === 'networkidle2' ? 2 : 0, - idleTime: NETWORK_IDLE_TIME, - }), - ] - : []) - ).pipe( - map(([{result}]) => { - return result; - }), - raceWith(timeout(ms), from(this.#abortDeferred.valueOrThrow())) - ); - - const result = await firstValueFrom(result$); - return this.#page.getNavigationResponse(result.navigation); } override waitForDevicePrompt(): never { @@ -264,18 +424,7 @@ export class BidiFrame extends Frame { } override get detached(): boolean { - return this.#disposed; - } - - [disposeSymbol](): void { - if (this.#disposed) { - return; - } - this.#disposed = true; - this.#abortDeferred.reject(new Error('Frame detached')); - this.#context.dispose(); - this.sandboxes[MAIN_SANDBOX][disposeSymbol](); - this.sandboxes[PUPPETEER_SANDBOX][disposeSymbol](); + return this.browsingContext.closed; } #exposedFunctions = new Map<string, ExposeableFunction<never[], unknown>>(); @@ -288,21 +437,27 @@ export class BidiFrame extends Frame { `Failed to add page binding with name ${name}: globalThis['${name}'] already exists!` ); } - const exposeable = new ExposeableFunction(this, name, apply); + const exposeable = await ExposeableFunction.from(this, name, apply); this.#exposedFunctions.set(name, exposeable); - try { - await exposeable.expose(); - } catch (error) { - this.#exposedFunctions.delete(name); - throw error; + } + + async removeExposedFunction(name: string): Promise<void> { + const exposedFunction = this.#exposedFunctions.get(name); + if (!exposedFunction) { + throw new Error( + `Failed to remove page binding with name ${name}: window['${name}'] does not exists!` + ); } + + this.#exposedFunctions.delete(name); + await exposedFunction[Symbol.asyncDispose](); } override waitForSelector<Selector extends string>( selector: Selector, options?: WaitForSelectorOptions ): Promise<ElementHandle<NodeFor<Selector>> | null> { - if (selector.startsWith('aria')) { + if (selector.startsWith('aria') && !this.page().browser().cdpSupported) { throw new UnsupportedOperation( 'ARIA selector is not supported for BiDi!' ); @@ -310,4 +465,124 @@ export class BidiFrame extends Frame { return super.waitForSelector(selector, options); } + + async createCDPSession(): Promise<CDPSession> { + const {sessionId} = await this.client.send('Target.attachToTarget', { + targetId: this._id, + flatten: true, + }); + return new BidiCdpSession(this, sessionId); + } + + @throwIfDetached + #waitForLoad$(options: WaitForOptions = {}): Observable<void> { + let {waitUntil = 'load'} = options; + const {timeout: ms = this.timeoutSettings.navigationTimeout()} = options; + + if (!Array.isArray(waitUntil)) { + waitUntil = [waitUntil]; + } + + const events = new Set<'load' | 'DOMContentLoaded'>(); + for (const lifecycleEvent of waitUntil) { + switch (lifecycleEvent) { + case 'load': { + events.add('load'); + break; + } + case 'domcontentloaded': { + events.add('DOMContentLoaded'); + break; + } + } + } + if (events.size === 0) { + return of(undefined); + } + + return combineLatest( + [...events].map(event => { + return fromEmitterEvent(this.browsingContext, event); + }) + ).pipe( + map(() => {}), + first(), + raceWith( + timeout(ms), + this.#detached$().pipe( + map(() => { + throw new Error('Frame detached.'); + }) + ) + ) + ); + } + + @throwIfDetached + #waitForNetworkIdle$(options: WaitForOptions = {}): Observable<void> { + let {waitUntil = 'load'} = options; + if (!Array.isArray(waitUntil)) { + waitUntil = [waitUntil]; + } + + let concurrency = Infinity; + for (const event of waitUntil) { + switch (event) { + case 'networkidle0': { + concurrency = Math.min(0, concurrency); + break; + } + case 'networkidle2': { + concurrency = Math.min(2, concurrency); + break; + } + } + } + if (concurrency === Infinity) { + return of(undefined); + } + + return this.page().waitForNetworkIdle$({ + idleTime: 500, + timeout: options.timeout ?? this.timeoutSettings.timeout(), + concurrency, + }); + } + + @throwIfDetached + async setFiles(element: BidiElementHandle, files: string[]): Promise<void> { + await this.browsingContext.setFiles( + // SAFETY: ElementHandles are always remote references. + element.remoteValue() as Bidi.Script.SharedReference, + files + ); + } +} + +function isConsoleLogEntry( + event: Bidi.Log.Entry +): event is Bidi.Log.ConsoleLogEntry { + return event.type === 'console'; +} + +function isJavaScriptLogEntry( + event: Bidi.Log.Entry +): event is Bidi.Log.JavascriptLogEntry { + return event.type === 'javascript'; +} + +function getStackTraceLocations( + stackTrace?: Bidi.Script.StackTrace +): ConsoleMessageLocation[] { + const stackTraceLocations: ConsoleMessageLocation[] = []; + if (stackTrace) { + for (const callFrame of stackTrace.callFrames) { + stackTraceLocations.push({ + url: callFrame.url, + lineNumber: callFrame.lineNumber, + columnNumber: callFrame.columnNumber, + }); + } + } + return stackTraceLocations; } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPRequest.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPRequest.ts index 57cb801b8c..e75bb0cf3c 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPRequest.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPRequest.ts @@ -5,106 +5,126 @@ */ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; -import type {Frame} from '../api/Frame.js'; +import type {CDPSession} from '../api/CDPSession.js'; import type { ContinueRequestOverrides, ResponseForRequest, } from '../api/HTTPRequest.js'; import {HTTPRequest, type ResourceType} from '../api/HTTPRequest.js'; +import {PageEvent} from '../api/Page.js'; import {UnsupportedOperation} from '../common/Errors.js'; -import type {BidiHTTPResponse} from './HTTPResponse.js'; +import type {Request} from './core/Request.js'; +import type {BidiFrame} from './Frame.js'; +import {BidiHTTPResponse} from './HTTPResponse.js'; + +export const requests = new WeakMap<Request, BidiHTTPRequest>(); /** * @internal */ export class BidiHTTPRequest extends HTTPRequest { - override _response: BidiHTTPResponse | null = null; - override _redirectChain: BidiHTTPRequest[]; - _navigationId: string | null; - - #url: string; - #resourceType: ResourceType; - - #method: string; - #postData?: string; - #headers: Record<string, string> = {}; - #initiator: Bidi.Network.Initiator; - #frame: Frame | null; - - constructor( - event: Bidi.Network.BeforeRequestSentParameters, - frame: Frame | null, - redirectChain: BidiHTTPRequest[] = [] - ) { + static from( + bidiRequest: Request, + frame: BidiFrame | undefined + ): BidiHTTPRequest { + const request = new BidiHTTPRequest(bidiRequest, frame); + request.#initialize(); + return request; + } + + #redirect: BidiHTTPRequest | undefined; + #response: BidiHTTPResponse | null = null; + override readonly id: string; + readonly #frame: BidiFrame | undefined; + readonly #request: Request; + + private constructor(request: Request, frame: BidiFrame | undefined) { super(); + requests.set(request, this); - this.#url = event.request.url; - this.#resourceType = event.initiator.type.toLowerCase() as ResourceType; - this.#method = event.request.method; - this.#postData = undefined; - this.#initiator = event.initiator; + this.#request = request; this.#frame = frame; - - this._requestId = event.request.request; - this._redirectChain = redirectChain; - this._navigationId = event.navigation; - - for (const header of event.request.headers) { - // TODO: How to handle Binary Headers - // https://w3c.github.io/webdriver-bidi/#type-network-Header - if (header.value.type === 'string') { - this.#headers[header.name.toLowerCase()] = header.value.value; - } - } + this.id = request.id; } - override get client(): never { + override get client(): CDPSession { throw new UnsupportedOperation(); } + #initialize() { + this.#request.on('redirect', request => { + this.#redirect = BidiHTTPRequest.from(request, this.#frame); + }); + this.#request.once('success', data => { + this.#response = BidiHTTPResponse.from(data, this); + }); + + this.#frame?.page().trustedEmitter.emit(PageEvent.Request, this); + } + override url(): string { - return this.#url; + return this.#request.url; } override resourceType(): ResourceType { - return this.#resourceType; + return this.initiator().type.toLowerCase() as ResourceType; } override method(): string { - return this.#method; + return this.#request.method; } override postData(): string | undefined { - return this.#postData; + throw new UnsupportedOperation(); } override hasPostData(): boolean { - return this.#postData !== undefined; + throw new UnsupportedOperation(); } override async fetchPostData(): Promise<string | undefined> { - return this.#postData; + throw new UnsupportedOperation(); } override headers(): Record<string, string> { - return this.#headers; + const headers: Record<string, string> = {}; + for (const header of this.#request.headers) { + headers[header.name.toLowerCase()] = header.value.value; + } + return headers; } override response(): BidiHTTPResponse | null { - return this._response; + return this.#response; + } + + override failure(): {errorText: string} | null { + if (this.#request.error === undefined) { + return null; + } + return {errorText: this.#request.error}; } override isNavigationRequest(): boolean { - return Boolean(this._navigationId); + return this.#request.navigation !== undefined; } override initiator(): Bidi.Network.Initiator { - return this.#initiator; + return this.#request.initiator; } override redirectChain(): BidiHTTPRequest[] { - return this._redirectChain.slice(); + if (this.#redirect === undefined) { + return []; + } + const redirects = [this.#redirect]; + for (const redirect of redirects) { + if (redirect.#redirect !== undefined) { + redirects.push(redirect.#redirect); + } + } + return redirects; } override enqueueInterceptAction( @@ -114,8 +134,8 @@ export class BidiHTTPRequest extends HTTPRequest { void pendingHandler(); } - override frame(): Frame | null { - return this.#frame; + override frame(): BidiFrame | null { + return this.#frame ?? null; } override continueRequestOverrides(): never { @@ -156,8 +176,4 @@ export class BidiHTTPRequest extends HTTPRequest { ): never { throw new UnsupportedOperation(); } - - override failure(): never { - throw new UnsupportedOperation(); - } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPResponse.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPResponse.ts index ce28820a65..bad44ff089 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPResponse.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPResponse.ts @@ -7,11 +7,10 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; import type Protocol from 'devtools-protocol'; import type {Frame} from '../api/Frame.js'; -import { - HTTPResponse as HTTPResponse, - type RemoteAddress, -} from '../api/HTTPResponse.js'; +import {HTTPResponse, type RemoteAddress} from '../api/HTTPResponse.js'; +import {PageEvent} from '../api/Page.js'; import {UnsupportedOperation} from '../common/Errors.js'; +import {invokeAtMostOnceForArguments} from '../util/decorators.js'; import type {BidiHTTPRequest} from './HTTPRequest.js'; @@ -19,62 +18,62 @@ import type {BidiHTTPRequest} from './HTTPRequest.js'; * @internal */ export class BidiHTTPResponse extends HTTPResponse { + static from( + data: Bidi.Network.ResponseData, + request: BidiHTTPRequest + ): BidiHTTPResponse { + const response = new BidiHTTPResponse(data, request); + response.#initialize(); + return response; + } + + #data: Bidi.Network.ResponseData; #request: BidiHTTPRequest; - #remoteAddress: RemoteAddress; - #status: number; - #statusText: string; - #url: string; - #fromCache: boolean; - #headers: Record<string, string> = {}; - #timings: Record<string, string> | null; - - constructor( - request: BidiHTTPRequest, - {response}: Bidi.Network.ResponseCompletedParameters + + private constructor( + data: Bidi.Network.ResponseData, + request: BidiHTTPRequest ) { super(); + this.#data = data; this.#request = request; + } - this.#remoteAddress = { - ip: '', - port: -1, - }; - - this.#url = response.url; - this.#fromCache = response.fromCache; - this.#status = response.status; - this.#statusText = response.statusText; - // TODO: File and issue with BiDi spec - this.#timings = null; - - // TODO: Removed once the Firefox implementation is compliant with https://w3c.github.io/webdriver-bidi/#get-the-response-data. - for (const header of response.headers || []) { - // TODO: How to handle Binary Headers - // https://w3c.github.io/webdriver-bidi/#type-network-Header - if (header.value.type === 'string') { - this.#headers[header.name.toLowerCase()] = header.value.value; - } - } + #initialize() { + this.#request.frame()?.page().trustedEmitter.emit(PageEvent.Response, this); } + @invokeAtMostOnceForArguments override remoteAddress(): RemoteAddress { - return this.#remoteAddress; + return { + ip: '', + port: -1, + }; } override url(): string { - return this.#url; + return this.#data.url; } override status(): number { - return this.#status; + return this.#data.status; } override statusText(): string { - return this.#statusText; + return this.#data.statusText; } override headers(): Record<string, string> { - return this.#headers; + const headers: Record<string, string> = {}; + // TODO: Remove once the Firefox implementation is compliant with https://w3c.github.io/webdriver-bidi/#get-the-response-data. + for (const header of this.#data.headers || []) { + // TODO: How to handle Binary Headers + // https://w3c.github.io/webdriver-bidi/#type-network-Header + if (header.value.type === 'string') { + headers[header.name.toLowerCase()] = header.value.value; + } + } + return headers; } override request(): BidiHTTPRequest { @@ -82,11 +81,12 @@ export class BidiHTTPResponse extends HTTPResponse { } override fromCache(): boolean { - return this.#fromCache; + return this.#data.fromCache; } override timing(): Protocol.Network.ResourceTiming | null { - return this.#timings as any; + // TODO: File and issue with BiDi spec + throw new UnsupportedOperation(); } override frame(): Frame | null { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Input.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Input.ts index 5406556d64..dc70850c12 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Input.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Input.ts @@ -12,9 +12,9 @@ import { Mouse, MouseButton, Touchscreen, + type KeyboardTypeOptions, type KeyDownOptions, type KeyPressOptions, - type KeyboardTypeOptions, type MouseClickOptions, type MouseMoveOptions, type MouseOptions, @@ -23,7 +23,6 @@ import { import {UnsupportedOperation} from '../common/Errors.js'; import type {KeyInput} from '../common/USKeyboardLayout.js'; -import type {BrowsingContext} from './BrowsingContext.js'; import type {BidiPage} from './Page.js'; const enum InputId { @@ -288,39 +287,33 @@ export class BidiKeyboard extends Keyboard { key: KeyInput, _options?: Readonly<KeyDownOptions> ): Promise<void> { - await this.#page.connection.send('input.performActions', { - context: this.#page.mainFrame()._id, - actions: [ - { - type: SourceActionsType.Key, - id: InputId.Keyboard, - actions: [ - { - type: ActionType.KeyDown, - value: getBidiKeyValue(key), - }, - ], - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Key, + id: InputId.Keyboard, + actions: [ + { + type: ActionType.KeyDown, + value: getBidiKeyValue(key), + }, + ], + }, + ]); } override async up(key: KeyInput): Promise<void> { - await this.#page.connection.send('input.performActions', { - context: this.#page.mainFrame()._id, - actions: [ - { - type: SourceActionsType.Key, - id: InputId.Keyboard, - actions: [ - { - type: ActionType.KeyUp, - value: getBidiKeyValue(key), - }, - ], - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Key, + id: InputId.Keyboard, + actions: [ + { + type: ActionType.KeyUp, + value: getBidiKeyValue(key), + }, + ], + }, + ]); } override async press( @@ -344,16 +337,13 @@ export class BidiKeyboard extends Keyboard { type: ActionType.KeyUp, value: getBidiKeyValue(key), }); - await this.#page.connection.send('input.performActions', { - context: this.#page.mainFrame()._id, - actions: [ - { - type: SourceActionsType.Key, - id: InputId.Keyboard, - actions, - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Key, + id: InputId.Keyboard, + actions, + }, + ]); } override async type( @@ -396,16 +386,13 @@ export class BidiKeyboard extends Keyboard { ); } } - await this.#page.connection.send('input.performActions', { - context: this.#page.mainFrame()._id, - actions: [ - { - type: SourceActionsType.Key, - id: InputId.Keyboard, - actions, - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Key, + id: InputId.Keyboard, + actions, + }, + ]); } override async sendCharacter(char: string): Promise<void> { @@ -460,19 +447,17 @@ const getBidiButton = (button: MouseButton) => { * @internal */ export class BidiMouse extends Mouse { - #context: BrowsingContext; + #page: BidiPage; #lastMovePoint: Point = {x: 0, y: 0}; - constructor(context: BrowsingContext) { + constructor(page: BidiPage) { super(); - this.#context = context; + this.#page = page; } override async reset(): Promise<void> { this.#lastMovePoint = {x: 0, y: 0}; - await this.#context.connection.send('input.releaseActions', { - context: this.#context.id, - }); + await this.#page.mainFrame().browsingContext.releaseActions(); } override async move( @@ -502,52 +487,43 @@ export class BidiMouse extends Mouse { }); // https://w3c.github.io/webdriver-bidi/#command-input-performActions:~:text=input.PointerMoveAction%20%3D%20%7B%0A%20%20type%3A%20%22pointerMove%22%2C%0A%20%20x%3A%20js%2Dint%2C this.#lastMovePoint = to; - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Pointer, - id: InputId.Mouse, - actions, - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Pointer, + id: InputId.Mouse, + actions, + }, + ]); } override async down(options: Readonly<MouseOptions> = {}): Promise<void> { - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Pointer, - id: InputId.Mouse, - actions: [ - { - type: ActionType.PointerDown, - button: getBidiButton(options.button ?? MouseButton.Left), - }, - ], - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Pointer, + id: InputId.Mouse, + actions: [ + { + type: ActionType.PointerDown, + button: getBidiButton(options.button ?? MouseButton.Left), + }, + ], + }, + ]); } override async up(options: Readonly<MouseOptions> = {}): Promise<void> { - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Pointer, - id: InputId.Mouse, - actions: [ - { - type: ActionType.PointerUp, - button: getBidiButton(options.button ?? MouseButton.Left), - }, - ], - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Pointer, + id: InputId.Mouse, + actions: [ + { + type: ActionType.PointerUp, + button: getBidiButton(options.button ?? MouseButton.Left), + }, + ], + }, + ]); } override async click( @@ -582,41 +558,35 @@ export class BidiMouse extends Mouse { }); } actions.push(pointerUpAction); - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Pointer, - id: InputId.Mouse, - actions, - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Pointer, + id: InputId.Mouse, + actions, + }, + ]); } override async wheel( options: Readonly<MouseWheelOptions> = {} ): Promise<void> { - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Wheel, - id: InputId.Wheel, - actions: [ - { - type: ActionType.Scroll, - ...(this.#lastMovePoint ?? { - x: 0, - y: 0, - }), - deltaX: options.deltaX ?? 0, - deltaY: options.deltaY ?? 0, - }, - ], - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Wheel, + id: InputId.Wheel, + actions: [ + { + type: ActionType.Scroll, + ...(this.#lastMovePoint ?? { + x: 0, + y: 0, + }), + deltaX: options.deltaX ?? 0, + deltaY: options.deltaY ?? 0, + }, + ], + }, + ]); } override drag(): never { @@ -644,11 +614,11 @@ export class BidiMouse extends Mouse { * @internal */ export class BidiTouchscreen extends Touchscreen { - #context: BrowsingContext; + #page: BidiPage; - constructor(context: BrowsingContext) { + constructor(page: BidiPage) { super(); - this.#context = context; + this.#page = page; } override async touchStart( @@ -656,30 +626,27 @@ export class BidiTouchscreen extends Touchscreen { y: number, options: BidiTouchMoveOptions = {} ): Promise<void> { - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Pointer, - id: InputId.Finger, - parameters: { - pointerType: Bidi.Input.PointerType.Touch, - }, - actions: [ - { - type: ActionType.PointerMove, - x: Math.round(x), - y: Math.round(y), - origin: options.origin, - }, - { - type: ActionType.PointerDown, - button: 0, - }, - ], + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Pointer, + id: InputId.Finger, + parameters: { + pointerType: Bidi.Input.PointerType.Touch, }, - ], - }); + actions: [ + { + type: ActionType.PointerMove, + x: Math.round(x), + y: Math.round(y), + origin: options.origin, + }, + { + type: ActionType.PointerDown, + button: 0, + }, + ], + }, + ]); } override async touchMove( @@ -687,46 +654,40 @@ export class BidiTouchscreen extends Touchscreen { y: number, options: BidiTouchMoveOptions = {} ): Promise<void> { - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Pointer, - id: InputId.Finger, - parameters: { - pointerType: Bidi.Input.PointerType.Touch, - }, - actions: [ - { - type: ActionType.PointerMove, - x: Math.round(x), - y: Math.round(y), - origin: options.origin, - }, - ], + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Pointer, + id: InputId.Finger, + parameters: { + pointerType: Bidi.Input.PointerType.Touch, }, - ], - }); + actions: [ + { + type: ActionType.PointerMove, + x: Math.round(x), + y: Math.round(y), + origin: options.origin, + }, + ], + }, + ]); } override async touchEnd(): Promise<void> { - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Pointer, - id: InputId.Finger, - parameters: { - pointerType: Bidi.Input.PointerType.Touch, - }, - actions: [ - { - type: ActionType.PointerUp, - button: 0, - }, - ], + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Pointer, + id: InputId.Finger, + parameters: { + pointerType: Bidi.Input.PointerType.Touch, }, - ], - }); + actions: [ + { + type: ActionType.PointerUp, + button: 0, + }, + ], + }, + ]); } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/JSHandle.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/JSHandle.ts index 7104601553..10f564f78a 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/JSHandle.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/JSHandle.ts @@ -12,29 +12,28 @@ import {UnsupportedOperation} from '../common/Errors.js'; import {BidiDeserializer} from './Deserializer.js'; import type {BidiRealm} from './Realm.js'; -import type {Sandbox} from './Sandbox.js'; -import {releaseReference} from './util.js'; /** * @internal */ export class BidiJSHandle<T = unknown> extends JSHandle<T> { - #disposed = false; - readonly #sandbox: Sandbox; + static from<T>( + value: Bidi.Script.RemoteValue, + realm: BidiRealm + ): BidiJSHandle<T> { + return new BidiJSHandle(value, realm); + } + readonly #remoteValue: Bidi.Script.RemoteValue; - constructor(sandbox: Sandbox, remoteValue: Bidi.Script.RemoteValue) { - super(); - this.#sandbox = sandbox; - this.#remoteValue = remoteValue; - } + override readonly realm: BidiRealm; - context(): BidiRealm { - return this.realm.environment.context(); - } + #disposed = false; - override get realm(): Sandbox { - return this.#sandbox; + constructor(value: Bidi.Script.RemoteValue, realm: BidiRealm) { + super(); + this.#remoteValue = value; + this.realm = realm; } override get disposed(): boolean { @@ -56,12 +55,7 @@ export class BidiJSHandle<T = unknown> extends JSHandle<T> { return; } this.#disposed = true; - if ('handle' in this.#remoteValue) { - await releaseReference( - this.context(), - this.#remoteValue as Bidi.Script.RemoteReference - ); - } + await this.realm.destroyHandles([this]); } get isPrimitiveValue(): boolean { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/NetworkManager.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/NetworkManager.ts deleted file mode 100644 index 2caaf0ad50..0000000000 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/NetworkManager.ts +++ /dev/null @@ -1,155 +0,0 @@ -/** - * @license - * Copyright 2023 Google Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; - -import {EventEmitter, EventSubscription} from '../common/EventEmitter.js'; -import { - NetworkManagerEvent, - type NetworkManagerEvents, -} from '../common/NetworkManagerEvents.js'; -import {DisposableStack} from '../util/disposable.js'; - -import type {BidiConnection} from './Connection.js'; -import type {BidiFrame} from './Frame.js'; -import {BidiHTTPRequest} from './HTTPRequest.js'; -import {BidiHTTPResponse} from './HTTPResponse.js'; -import type {BidiPage} from './Page.js'; - -/** - * @internal - */ -export class BidiNetworkManager extends EventEmitter<NetworkManagerEvents> { - #connection: BidiConnection; - #page: BidiPage; - #subscriptions = new DisposableStack(); - - #requestMap = new Map<string, BidiHTTPRequest>(); - #navigationMap = new Map<string, BidiHTTPResponse>(); - - constructor(connection: BidiConnection, page: BidiPage) { - super(); - this.#connection = connection; - this.#page = page; - - // TODO: Subscribe to the Frame individually - this.#subscriptions.use( - new EventSubscription( - this.#connection, - 'network.beforeRequestSent', - this.#onBeforeRequestSent.bind(this) - ) - ); - this.#subscriptions.use( - new EventSubscription( - this.#connection, - 'network.responseStarted', - this.#onResponseStarted.bind(this) - ) - ); - this.#subscriptions.use( - new EventSubscription( - this.#connection, - 'network.responseCompleted', - this.#onResponseCompleted.bind(this) - ) - ); - this.#subscriptions.use( - new EventSubscription( - this.#connection, - 'network.fetchError', - this.#onFetchError.bind(this) - ) - ); - } - - #onBeforeRequestSent(event: Bidi.Network.BeforeRequestSentParameters): void { - const frame = this.#page.frame(event.context ?? ''); - if (!frame) { - return; - } - const request = this.#requestMap.get(event.request.request); - let upsertRequest: BidiHTTPRequest; - if (request) { - request._redirectChain.push(request); - upsertRequest = new BidiHTTPRequest(event, frame, request._redirectChain); - } else { - upsertRequest = new BidiHTTPRequest(event, frame, []); - } - this.#requestMap.set(event.request.request, upsertRequest); - this.emit(NetworkManagerEvent.Request, upsertRequest); - } - - #onResponseStarted(_event: Bidi.Network.ResponseStartedParameters) {} - - #onResponseCompleted(event: Bidi.Network.ResponseCompletedParameters): void { - const request = this.#requestMap.get(event.request.request); - if (!request) { - return; - } - const response = new BidiHTTPResponse(request, event); - request._response = response; - if (event.navigation) { - this.#navigationMap.set(event.navigation, response); - } - if (response.fromCache()) { - this.emit(NetworkManagerEvent.RequestServedFromCache, request); - } - this.emit(NetworkManagerEvent.Response, response); - this.emit(NetworkManagerEvent.RequestFinished, request); - } - - #onFetchError(event: Bidi.Network.FetchErrorParameters) { - const request = this.#requestMap.get(event.request.request); - if (!request) { - return; - } - request._failureText = event.errorText; - this.emit(NetworkManagerEvent.RequestFailed, request); - this.#requestMap.delete(event.request.request); - } - - getNavigationResponse(navigationId?: string | null): BidiHTTPResponse | null { - if (!navigationId) { - return null; - } - const response = this.#navigationMap.get(navigationId); - - return response ?? null; - } - - inFlightRequestsCount(): number { - let inFlightRequestCounter = 0; - for (const request of this.#requestMap.values()) { - if (!request.response() || request._failureText) { - inFlightRequestCounter++; - } - } - - return inFlightRequestCounter; - } - - clearMapAfterFrameDispose(frame: BidiFrame): void { - for (const [id, request] of this.#requestMap.entries()) { - if (request.frame() === frame) { - this.#requestMap.delete(id); - } - } - - for (const [id, response] of this.#navigationMap.entries()) { - if (response.frame() === frame) { - this.#navigationMap.delete(id); - } - } - } - - dispose(): void { - this.removeAllListeners(); - this.#requestMap.clear(); - this.#navigationMap.clear(); - this.#subscriptions.dispose(); - } -} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Page.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Page.ts index 053d23b63a..c662496a18 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Page.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Page.ts @@ -4,210 +4,115 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {Readable} from 'stream'; - -import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; +import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; import type Protocol from 'devtools-protocol'; -import { - firstValueFrom, - from, - map, - raceWith, - zip, -} from '../../third_party/rxjs/rxjs.js'; +import {firstValueFrom, from, raceWith} from '../../third_party/rxjs/rxjs.js'; import type {CDPSession} from '../api/CDPSession.js'; import type {BoundingBox} from '../api/ElementHandle.js'; import type {WaitForOptions} from '../api/Frame.js'; import type {HTTPResponse} from '../api/HTTPResponse.js'; +import type { + MediaFeature, + GeolocationOptions, + PageEvents, +} from '../api/Page.js'; import { Page, PageEvent, - type GeolocationOptions, - type MediaFeature, type NewDocumentScriptEvaluation, type ScreenshotOptions, } from '../api/Page.js'; import {Accessibility} from '../cdp/Accessibility.js'; import {Coverage} from '../cdp/Coverage.js'; -import {EmulationManager as CdpEmulationManager} from '../cdp/EmulationManager.js'; -import {FrameTree} from '../cdp/FrameTree.js'; +import {EmulationManager} from '../cdp/EmulationManager.js'; import {Tracing} from '../cdp/Tracing.js'; -import { - ConsoleMessage, - type ConsoleMessageLocation, -} from '../common/ConsoleMessage.js'; -import {TargetCloseError, UnsupportedOperation} from '../common/Errors.js'; -import type {Handler} from '../common/EventEmitter.js'; -import {NetworkManagerEvent} from '../common/NetworkManagerEvents.js'; +import type {Cookie, CookieParam, CookieSameSite} from '../common/Cookie.js'; +import type {DeleteCookiesRequest} from '../common/Cookie.js'; +import {UnsupportedOperation} from '../common/Errors.js'; +import {EventEmitter} from '../common/EventEmitter.js'; import type {PDFOptions} from '../common/PDFOptions.js'; import type {Awaitable} from '../common/types.js'; -import { - debugError, - evaluationString, - NETWORK_IDLE_TIME, - parsePDFOptions, - timeout, - validateDialogType, -} from '../common/util.js'; +import {evaluationString, parsePDFOptions, timeout} from '../common/util.js'; import type {Viewport} from '../common/Viewport.js'; import {assert} from '../util/assert.js'; -import {Deferred} from '../util/Deferred.js'; -import {disposeSymbol} from '../util/disposable.js'; +import {bubble} from '../util/decorators.js'; import {isErrorLike} from '../util/ErrorLike.js'; import type {BidiBrowser} from './Browser.js'; import type {BidiBrowserContext} from './BrowserContext.js'; -import { - BrowsingContextEvent, - CdpSessionWrapper, - type BrowsingContext, -} from './BrowsingContext.js'; -import type {BidiConnection} from './Connection.js'; -import {BidiDeserializer} from './Deserializer.js'; -import {BidiDialog} from './Dialog.js'; +import type {BidiCdpSession} from './CDPSession.js'; +import type {BrowsingContext} from './core/BrowsingContext.js'; import {BidiElementHandle} from './ElementHandle.js'; -import {EmulationManager} from './EmulationManager.js'; import {BidiFrame} from './Frame.js'; -import type {BidiHTTPRequest} from './HTTPRequest.js'; import type {BidiHTTPResponse} from './HTTPResponse.js'; import {BidiKeyboard, BidiMouse, BidiTouchscreen} from './Input.js'; import type {BidiJSHandle} from './JSHandle.js'; -import {getBiDiReadinessState, rewriteNavigationError} from './lifecycle.js'; -import {BidiNetworkManager} from './NetworkManager.js'; -import {createBidiHandle} from './Realm.js'; -import type {BiDiPageTarget} from './Target.js'; +import {rewriteNavigationError} from './util.js'; +import type {BidiWebWorker} from './WebWorker.js'; /** * @internal */ export class BidiPage extends Page { - #accessibility: Accessibility; - #connection: BidiConnection; - #frameTree = new FrameTree<BidiFrame>(); - #networkManager: BidiNetworkManager; - #viewport: Viewport | null = null; - #closedDeferred = Deferred.create<never, TargetCloseError>(); - #subscribedEvents = new Map<Bidi.Event['method'], Handler<any>>([ - ['log.entryAdded', this.#onLogEntryAdded.bind(this)], - ['browsingContext.load', this.#onFrameLoaded.bind(this)], - [ - 'browsingContext.fragmentNavigated', - this.#onFrameFragmentNavigated.bind(this), - ], - [ - 'browsingContext.domContentLoaded', - this.#onFrameDOMContentLoaded.bind(this), - ], - ['browsingContext.userPromptOpened', this.#onDialog.bind(this)], - ]); - readonly #networkManagerEvents = [ - [ - NetworkManagerEvent.Request, - (request: BidiHTTPRequest) => { - this.emit(PageEvent.Request, request); - }, - ], - [ - NetworkManagerEvent.RequestServedFromCache, - (request: BidiHTTPRequest) => { - this.emit(PageEvent.RequestServedFromCache, request); - }, - ], - [ - NetworkManagerEvent.RequestFailed, - (request: BidiHTTPRequest) => { - this.emit(PageEvent.RequestFailed, request); - }, - ], - [ - NetworkManagerEvent.RequestFinished, - (request: BidiHTTPRequest) => { - this.emit(PageEvent.RequestFinished, request); - }, - ], - [ - NetworkManagerEvent.Response, - (response: BidiHTTPResponse) => { - this.emit(PageEvent.Response, response); - }, - ], - ] as const; - - readonly #browsingContextEvents = new Map<symbol, Handler<any>>([ - [BrowsingContextEvent.Created, this.#onContextCreated.bind(this)], - [BrowsingContextEvent.Destroyed, this.#onContextDestroyed.bind(this)], - ]); - #tracing: Tracing; - #coverage: Coverage; - #cdpEmulationManager: CdpEmulationManager; - #emulationManager: EmulationManager; - #mouse: BidiMouse; - #touchscreen: BidiTouchscreen; - #keyboard: BidiKeyboard; - #browsingContext: BrowsingContext; - #browserContext: BidiBrowserContext; - #target: BiDiPageTarget; - - _client(): CDPSession { - return this.mainFrame().context().cdpSession; - } - - constructor( - browsingContext: BrowsingContext, + static from( browserContext: BidiBrowserContext, - target: BiDiPageTarget - ) { - super(); - this.#browsingContext = browsingContext; - this.#browserContext = browserContext; - this.#target = target; - this.#connection = browsingContext.connection; + browsingContext: BrowsingContext + ): BidiPage { + const page = new BidiPage(browserContext, browsingContext); + page.#initialize(); + return page; + } - for (const [event, subscriber] of this.#browsingContextEvents) { - this.#browsingContext.on(event, subscriber); - } + @bubble() + accessor trustedEmitter = new EventEmitter<PageEvents>(); - this.#networkManager = new BidiNetworkManager(this.#connection, this); + readonly #browserContext: BidiBrowserContext; + readonly #frame: BidiFrame; + #viewport: Viewport | null = null; + readonly #workers = new Set<BidiWebWorker>(); - for (const [event, subscriber] of this.#subscribedEvents) { - this.#connection.on(event, subscriber); - } + readonly keyboard: BidiKeyboard; + readonly mouse: BidiMouse; + readonly touchscreen: BidiTouchscreen; + readonly accessibility: Accessibility; + readonly tracing: Tracing; + readonly coverage: Coverage; + readonly #cdpEmulationManager: EmulationManager; - for (const [event, subscriber] of this.#networkManagerEvents) { - // TODO: remove any - this.#networkManager.on(event, subscriber as any); - } + _client(): BidiCdpSession { + return this.#frame.client; + } - const frame = new BidiFrame( - this, - this.#browsingContext, - this._timeoutSettings, - this.#browsingContext.parent - ); - this.#frameTree.addFrame(frame); - this.emit(PageEvent.FrameAttached, frame); + private constructor( + browserContext: BidiBrowserContext, + browsingContext: BrowsingContext + ) { + super(); + this.#browserContext = browserContext; + this.#frame = BidiFrame.from(this, browsingContext); - // TODO: https://github.com/w3c/webdriver-bidi/issues/443 - this.#accessibility = new Accessibility( - this.mainFrame().context().cdpSession - ); - this.#tracing = new Tracing(this.mainFrame().context().cdpSession); - this.#coverage = new Coverage(this.mainFrame().context().cdpSession); - this.#cdpEmulationManager = new CdpEmulationManager( - this.mainFrame().context().cdpSession - ); - this.#emulationManager = new EmulationManager(browsingContext); - this.#mouse = new BidiMouse(this.mainFrame().context()); - this.#touchscreen = new BidiTouchscreen(this.mainFrame().context()); - this.#keyboard = new BidiKeyboard(this); + this.#cdpEmulationManager = new EmulationManager(this.#frame.client); + this.accessibility = new Accessibility(this.#frame.client); + this.tracing = new Tracing(this.#frame.client); + this.coverage = new Coverage(this.#frame.client); + this.keyboard = new BidiKeyboard(this); + this.mouse = new BidiMouse(this); + this.touchscreen = new BidiTouchscreen(this); } - /** - * @internal - */ - get connection(): BidiConnection { - return this.#connection; + #initialize() { + this.#frame.browsingContext.on('closed', () => { + this.trustedEmitter.emit(PageEvent.Close, undefined); + this.trustedEmitter.removeAllListeners(); + }); + + this.trustedEmitter.on(PageEvent.WorkerCreated, worker => { + this.#workers.add(worker as BidiWebWorker); + }); + this.trustedEmitter.on(PageEvent.WorkerDestroyed, worker => { + this.#workers.delete(worker as BidiWebWorker); + }); } override async setUserAgent( @@ -234,46 +139,15 @@ export class BidiPage extends Page { prototypeHandle.id, 'Prototype JSHandle must not be referencing primitive value' ); - const response = await this.mainFrame().client.send( - 'Runtime.queryObjects', - { - prototypeObjectId: prototypeHandle.id, - } - ); - return createBidiHandle(this.mainFrame().mainRealm(), { + const response = await this.#frame.client.send('Runtime.queryObjects', { + prototypeObjectId: prototypeHandle.id, + }); + return this.#frame.mainRealm().createHandle({ type: 'array', handle: response.objects.objectId, }) as BidiJSHandle<Prototype[]>; } - _setBrowserContext(browserContext: BidiBrowserContext): void { - this.#browserContext = browserContext; - } - - override get accessibility(): Accessibility { - return this.#accessibility; - } - - override get tracing(): Tracing { - return this.#tracing; - } - - override get coverage(): Coverage { - return this.#coverage; - } - - override get mouse(): BidiMouse { - return this.#mouse; - } - - override get touchscreen(): BidiTouchscreen { - return this.#touchscreen; - } - - override get keyboard(): BidiKeyboard { - return this.#keyboard; - } - override browser(): BidiBrowser { return this.browserContext().browser(); } @@ -283,14 +157,9 @@ export class BidiPage extends Page { } override mainFrame(): BidiFrame { - const mainFrame = this.#frameTree.getMainFrame(); - assert(mainFrame, 'Requesting main frame too early!'); - return mainFrame; + return this.#frame; } - /** - * @internal - */ async focusedFrame(): Promise<BidiFrame> { using frame = await this.mainFrame() .isolatedRealm() @@ -310,216 +179,38 @@ export class BidiPage extends Page { } override frames(): BidiFrame[] { - return Array.from(this.#frameTree.frames()); - } - - frame(frameId?: string): BidiFrame | null { - return this.#frameTree.getById(frameId ?? '') || null; - } - - childFrames(frameId: string): BidiFrame[] { - return this.#frameTree.childFrames(frameId); - } - - #onFrameLoaded(info: Bidi.BrowsingContext.NavigationInfo): void { - const frame = this.frame(info.context); - if (frame && this.mainFrame() === frame) { - this.emit(PageEvent.Load, undefined); - } - } - - #onFrameFragmentNavigated(info: Bidi.BrowsingContext.NavigationInfo): void { - const frame = this.frame(info.context); - if (frame) { - this.emit(PageEvent.FrameNavigated, frame); - } - } - - #onFrameDOMContentLoaded(info: Bidi.BrowsingContext.NavigationInfo): void { - const frame = this.frame(info.context); - if (frame) { - frame._hasStartedLoading = true; - if (this.mainFrame() === frame) { - this.emit(PageEvent.DOMContentLoaded, undefined); - } - this.emit(PageEvent.FrameNavigated, frame); - } - } - - #onContextCreated(context: BrowsingContext): void { - if ( - !this.frame(context.id) && - (this.frame(context.parent ?? '') || !this.#frameTree.getMainFrame()) - ) { - const frame = new BidiFrame( - this, - context, - this._timeoutSettings, - context.parent - ); - this.#frameTree.addFrame(frame); - if (frame !== this.mainFrame()) { - this.emit(PageEvent.FrameAttached, frame); - } - } - } - - #onContextDestroyed(context: BrowsingContext): void { - const frame = this.frame(context.id); - - if (frame) { - if (frame === this.mainFrame()) { - this.emit(PageEvent.Close, undefined); - } - this.#removeFramesRecursively(frame); - } - } - - #removeFramesRecursively(frame: BidiFrame): void { - for (const child of frame.childFrames()) { - this.#removeFramesRecursively(child); - } - frame[disposeSymbol](); - this.#networkManager.clearMapAfterFrameDispose(frame); - this.#frameTree.removeFrame(frame); - this.emit(PageEvent.FrameDetached, frame); - } - - #onLogEntryAdded(event: Bidi.Log.Entry): void { - const frame = this.frame(event.source.context); - if (!frame) { - return; - } - if (isConsoleLogEntry(event)) { - const args = event.args.map(arg => { - return createBidiHandle(frame.mainRealm(), arg); - }); - - const text = args - .reduce((value, arg) => { - const parsedValue = arg.isPrimitiveValue - ? BidiDeserializer.deserialize(arg.remoteValue()) - : arg.toString(); - return `${value} ${parsedValue}`; - }, '') - .slice(1); - - this.emit( - PageEvent.Console, - new ConsoleMessage( - event.method as any, - text, - args, - getStackTraceLocations(event.stackTrace) - ) - ); - } else if (isJavaScriptLogEntry(event)) { - const error = new Error(event.text ?? ''); - - const messageHeight = error.message.split('\n').length; - const messageLines = error.stack!.split('\n').splice(0, messageHeight); - - const stackLines = []; - if (event.stackTrace) { - for (const frame of event.stackTrace.callFrames) { - // Note we need to add `1` because the values are 0-indexed. - stackLines.push( - ` at ${frame.functionName || '<anonymous>'} (${frame.url}:${ - frame.lineNumber + 1 - }:${frame.columnNumber + 1})` - ); - if (stackLines.length >= Error.stackTraceLimit) { - break; - } - } - } - - error.stack = [...messageLines, ...stackLines].join('\n'); - this.emit(PageEvent.PageError, error); - } else { - debugError( - `Unhandled LogEntry with type "${event.type}", text "${event.text}" and level "${event.level}"` - ); - } - } - - #onDialog(event: Bidi.BrowsingContext.UserPromptOpenedParameters): void { - const frame = this.frame(event.context); - if (!frame) { - return; + const frames = [this.#frame]; + for (const frame of frames) { + frames.push(...frame.childFrames()); } - const type = validateDialogType(event.type); - - const dialog = new BidiDialog( - frame.context(), - type, - event.message, - event.defaultValue - ); - this.emit(PageEvent.Dialog, dialog); - } - - getNavigationResponse(id?: string | null): BidiHTTPResponse | null { - return this.#networkManager.getNavigationResponse(id); + return frames; } override isClosed(): boolean { - return this.#closedDeferred.finished(); + return this.#frame.detached; } override async close(options?: {runBeforeUnload?: boolean}): Promise<void> { - if (this.#closedDeferred.finished()) { + try { + await this.#frame.browsingContext.close(options?.runBeforeUnload); + } catch { return; } - - this.#closedDeferred.reject(new TargetCloseError('Page closed!')); - this.#networkManager.dispose(); - - await this.#connection.send('browsingContext.close', { - context: this.mainFrame()._id, - promptUnload: options?.runBeforeUnload ?? false, - }); - - this.emit(PageEvent.Close, undefined); - this.removeAllListeners(); } override async reload( options: WaitForOptions = {} ): Promise<BidiHTTPResponse | null> { - const { - waitUntil = 'load', - timeout: ms = this._timeoutSettings.navigationTimeout(), - } = options; - - const [readiness, networkIdle] = getBiDiReadinessState(waitUntil); - - const result$ = zip( - from( - this.#connection.send('browsingContext.reload', { - context: this.mainFrame()._id, - wait: readiness, - }) - ), - ...(networkIdle !== null - ? [ - this.waitForNetworkIdle$({ - timeout: ms, - concurrency: networkIdle === 'networkidle2' ? 2 : 0, - idleTime: NETWORK_IDLE_TIME, - }), - ] - : []) - ).pipe( - map(([{result}]) => { - return result; - }), - raceWith(timeout(ms), from(this.#closedDeferred.valueOrThrow())), - rewriteNavigationError(this.url(), ms) + const [response] = await Promise.all([ + this.#frame.waitForNavigation(options), + this.#frame.browsingContext.reload(), + ]).catch( + rewriteNavigationError( + this.url(), + options.timeout ?? this._timeoutSettings.navigationTimeout() + ) ); - - const result = await firstValueFrom(result$); - return this.getNavigationResponse(result.navigation); + return response; } override setDefaultNavigationTimeout(timeout: number): void { @@ -578,8 +269,19 @@ export class BidiPage extends Page { } override async setViewport(viewport: Viewport): Promise<void> { - if (!this.#browsingContext.supportsCdp()) { - await this.#emulationManager.emulateViewport(viewport); + if (!this.browser().cdpSupported) { + await this.#frame.browsingContext.setViewport({ + viewport: + viewport.width && viewport.height + ? { + width: viewport.width, + height: viewport.height, + } + : null, + devicePixelRatio: viewport.deviceScaleFactor + ? viewport.deviceScaleFactor + : null, + }); this.#viewport = viewport; return; } @@ -609,10 +311,9 @@ export class BidiPage extends Page { preferCSSPageSize, } = parsePDFOptions(options, 'cm'); const pageRanges = ranges ? ranges.split(', ') : []; - const {result} = await firstValueFrom( + const data = await firstValueFrom( from( - this.#connection.send('browsingContext.print', { - context: this.mainFrame()._id, + this.#frame.browsingContext.print({ background, margin, orientation: landscape ? 'landscape' : 'portrait', @@ -627,7 +328,7 @@ export class BidiPage extends Page { ).pipe(raceWith(timeout(ms))) ); - const buffer = Buffer.from(result.data, 'base64'); + const buffer = Buffer.from(data, 'base64'); await this._maybeWriteBufferToFile(path, buffer); @@ -636,19 +337,15 @@ export class BidiPage extends Page { override async createPDFStream( options?: PDFOptions | undefined - ): Promise<Readable> { + ): Promise<ReadableStream<Uint8Array>> { const buffer = await this.pdf(options); - try { - const {Readable} = await import('stream'); - return Readable.from(buffer); - } catch (error) { - if (error instanceof TypeError) { - throw new Error( - 'Can only pass a file path in a Node-like environment.' - ); - } - throw error; - } + + return new ReadableStream({ + start(controller) { + controller.enqueue(buffer); + controller.close(); + }, + }); } override async _screenshot( @@ -697,10 +394,7 @@ export class BidiPage extends Page { } } - const { - result: {data}, - } = await this.#connection.send('browsingContext.captureScreenshot', { - context: this.mainFrame()._id, + const data = await this.#frame.browsingContext.captureScreenshot({ origin: captureBeyondViewport ? 'document' : 'viewport', format: { type: `image/${type}`, @@ -712,19 +406,11 @@ export class BidiPage extends Page { } override async createCDPSession(): Promise<CDPSession> { - const {sessionId} = await this.mainFrame() - .context() - .cdpSession.send('Target.attachToTarget', { - targetId: this.mainFrame()._id, - flatten: true, - }); - return new CdpSessionWrapper(this.mainFrame().context(), sessionId); + return await this.#frame.createCDPSession(); } override async bringToFront(): Promise<void> { - await this.#connection.send('browsingContext.activate', { - context: this.mainFrame()._id, - }); + await this.#frame.browsingContext.activate(); } override async evaluateOnNewDocument< @@ -735,20 +421,16 @@ export class BidiPage extends Page { ...args: Params ): Promise<NewDocumentScriptEvaluation> { const expression = evaluationExpression(pageFunction, ...args); - const {result} = await this.#connection.send('script.addPreloadScript', { - functionDeclaration: expression, - contexts: [this.mainFrame()._id], - }); + const script = + await this.#frame.browsingContext.addPreloadScript(expression); - return {identifier: result.script}; + return {identifier: script}; } override async removeScriptToEvaluateOnNewDocument( id: string ): Promise<void> { - await this.#connection.send('script.removePreloadScript', { - script: id, - }); + await this.#frame.browsingContext.removePreloadScript(id); } override async exposeFunction<Args extends unknown[], Ret>( @@ -774,20 +456,37 @@ export class BidiPage extends Page { }); } + override async cookies(...urls: string[]): Promise<Cookie[]> { + const normalizedUrls = (urls.length ? urls : [this.url()]).map(url => { + return new URL(url); + }); + + const cookies = await this.#frame.browsingContext.getCookies(); + return cookies + .map(cookie => { + return bidiToPuppeteerCookie(cookie); + }) + .filter(cookie => { + return normalizedUrls.some(url => { + return testUrlMatchCookie(cookie, url); + }); + }); + } + override isServiceWorkerBypassed(): never { throw new UnsupportedOperation(); } - override target(): BiDiPageTarget { - return this.#target; + override target(): never { + throw new UnsupportedOperation(); } override waitForFileChooser(): never { throw new UnsupportedOperation(); } - override workers(): never { - throw new UnsupportedOperation(); + override workers(): BidiWebWorker[] { + return [...this.#workers]; } override setRequestInterception(): never { @@ -810,21 +509,98 @@ export class BidiPage extends Page { throw new UnsupportedOperation(); } - override cookies(): never { - throw new UnsupportedOperation(); - } + override async setCookie(...cookies: CookieParam[]): Promise<void> { + const pageURL = this.url(); + const pageUrlStartsWithHTTP = pageURL.startsWith('http'); + for (const cookie of cookies) { + let cookieUrl = cookie.url || ''; + if (!cookieUrl && pageUrlStartsWithHTTP) { + cookieUrl = pageURL; + } + assert( + cookieUrl !== 'about:blank', + `Blank page can not have cookie "${cookie.name}"` + ); + assert( + !String.prototype.startsWith.call(cookieUrl || '', 'data:'), + `Data URL page can not have cookie "${cookie.name}"` + ); - override setCookie(): never { - throw new UnsupportedOperation(); + const normalizedUrl = URL.canParse(cookieUrl) + ? new URL(cookieUrl) + : undefined; + + const domain = cookie.domain ?? normalizedUrl?.hostname; + assert( + domain !== undefined, + `At least one of the url and domain needs to be specified` + ); + + const bidiCookie: Bidi.Storage.PartialCookie = { + domain: domain, + name: cookie.name, + value: { + type: 'string', + value: cookie.value, + }, + ...(cookie.path !== undefined ? {path: cookie.path} : {}), + ...(cookie.httpOnly !== undefined ? {httpOnly: cookie.httpOnly} : {}), + ...(cookie.secure !== undefined ? {secure: cookie.secure} : {}), + ...(cookie.sameSite !== undefined + ? {sameSite: convertCookiesSameSiteCdpToBiDi(cookie.sameSite)} + : {}), + ...(cookie.expires !== undefined ? {expiry: cookie.expires} : {}), + // Chrome-specific properties. + ...cdpSpecificCookiePropertiesFromPuppeteerToBidi( + cookie, + 'sameParty', + 'sourceScheme', + 'priority', + 'url' + ), + }; + + if (cookie.partitionKey !== undefined) { + await this.browserContext().userContext.setCookie( + bidiCookie, + cookie.partitionKey + ); + } else { + await this.#frame.browsingContext.setCookie(bidiCookie); + } + } } - override deleteCookie(): never { - throw new UnsupportedOperation(); + override async deleteCookie( + ...cookies: DeleteCookiesRequest[] + ): Promise<void> { + await Promise.all( + cookies.map(async deleteCookieRequest => { + const cookieUrl = deleteCookieRequest.url ?? this.url(); + const normalizedUrl = URL.canParse(cookieUrl) + ? new URL(cookieUrl) + : undefined; + + const domain = deleteCookieRequest.domain ?? normalizedUrl?.hostname; + assert( + domain !== undefined, + `At least one of the url and domain needs to be specified` + ); + + const filter = { + domain: domain, + name: deleteCookieRequest.name, + ...(deleteCookieRequest.path !== undefined + ? {path: deleteCookieRequest.path} + : {}), + }; + await this.#frame.browsingContext.deleteCookie(filter); + }) + ); } - override removeExposedFunction(): never { - // TODO: Quick win? - throw new UnsupportedOperation(); + override async removeExposedFunction(name: string): Promise<void> { + await this.#frame.removeExposedFunction(name); } override authenticate(): never { @@ -848,7 +624,7 @@ export class BidiPage extends Page { override async goForward( options: WaitForOptions = {} ): Promise<HTTPResponse | null> { - return await this.#go(+1, options); + return await this.#go(1, options); } async #go( @@ -856,22 +632,19 @@ export class BidiPage extends Page { options: WaitForOptions ): Promise<HTTPResponse | null> { try { - const result = await Promise.all([ + const [response] = await Promise.all([ this.waitForNavigation(options), - this.#connection.send('browsingContext.traverseHistory', { - delta, - context: this.mainFrame()._id, - }), + this.#frame.browsingContext.traverseHistory(delta), ]); - return result[0]; - } catch (err) { + return response; + } catch (error) { // TODO: waitForNavigation should be cancelled if an error happens. - if (isErrorLike(err)) { - if (err.message.includes('no such history entry')) { + if (isErrorLike(error)) { + if (error.message.includes('no such history entry')) { return null; } } - throw err; + throw error; } } @@ -880,34 +653,137 @@ export class BidiPage extends Page { } } -function isConsoleLogEntry( - event: Bidi.Log.Entry -): event is Bidi.Log.ConsoleLogEntry { - return event.type === 'console'; +function evaluationExpression(fun: Function | string, ...args: unknown[]) { + return `() => {${evaluationString(fun, ...args)}}`; } -function isJavaScriptLogEntry( - event: Bidi.Log.Entry -): event is Bidi.Log.JavascriptLogEntry { - return event.type === 'javascript'; +/** + * Check domains match. + * According to cookies spec, this check should match subdomains as well, but CDP + * implementation does not do that, so this method matches only the exact domains, not + * what is written in the spec: + * https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.3 + */ +function testUrlMatchCookieHostname( + cookie: Cookie, + normalizedUrl: URL +): boolean { + const cookieDomain = cookie.domain.toLowerCase(); + const urlHostname = normalizedUrl.hostname.toLowerCase(); + return cookieDomain === urlHostname; } -function getStackTraceLocations( - stackTrace?: Bidi.Script.StackTrace -): ConsoleMessageLocation[] { - const stackTraceLocations: ConsoleMessageLocation[] = []; - if (stackTrace) { - for (const callFrame of stackTrace.callFrames) { - stackTraceLocations.push({ - url: callFrame.url, - lineNumber: callFrame.lineNumber, - columnNumber: callFrame.columnNumber, - }); +/** + * Check paths match. + * Spec: https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4 + */ +function testUrlMatchCookiePath(cookie: Cookie, normalizedUrl: URL): boolean { + const uriPath = normalizedUrl.pathname; + const cookiePath = cookie.path; + + if (uriPath === cookiePath) { + // The cookie-path and the request-path are identical. + return true; + } + if (uriPath.startsWith(cookiePath)) { + // The cookie-path is a prefix of the request-path. + if (cookiePath.endsWith('/')) { + // The last character of the cookie-path is %x2F ("/"). + return true; + } + if (uriPath[cookiePath.length] === '/') { + // The first character of the request-path that is not included in the cookie-path + // is a %x2F ("/") character. + return true; } } - return stackTraceLocations; + return false; } -function evaluationExpression(fun: Function | string, ...args: unknown[]) { - return `() => {${evaluationString(fun, ...args)}}`; +/** + * Checks the cookie matches the URL according to the spec: + */ +function testUrlMatchCookie(cookie: Cookie, url: URL): boolean { + const normalizedUrl = new URL(url); + assert(cookie !== undefined); + if (!testUrlMatchCookieHostname(cookie, normalizedUrl)) { + return false; + } + return testUrlMatchCookiePath(cookie, normalizedUrl); +} + +function bidiToPuppeteerCookie(bidiCookie: Bidi.Network.Cookie): Cookie { + return { + name: bidiCookie.name, + // Presents binary value as base64 string. + value: bidiCookie.value.value, + domain: bidiCookie.domain, + path: bidiCookie.path, + size: bidiCookie.size, + httpOnly: bidiCookie.httpOnly, + secure: bidiCookie.secure, + sameSite: convertCookiesSameSiteBiDiToCdp(bidiCookie.sameSite), + expires: bidiCookie.expiry ?? -1, + session: bidiCookie.expiry === undefined || bidiCookie.expiry <= 0, + // Extending with CDP-specific properties with `goog:` prefix. + ...cdpSpecificCookiePropertiesFromBidiToPuppeteer( + bidiCookie, + 'sameParty', + 'sourceScheme', + 'partitionKey', + 'partitionKeyOpaque', + 'priority' + ), + }; +} + +const CDP_SPECIFIC_PREFIX = 'goog:'; + +/** + * Gets CDP-specific properties from the BiDi cookie and returns them as a new object. + */ +function cdpSpecificCookiePropertiesFromBidiToPuppeteer( + bidiCookie: Bidi.Network.Cookie, + ...propertyNames: Array<keyof Cookie> +): Partial<Cookie> { + const result: Partial<Cookie> = {}; + for (const property of propertyNames) { + if (bidiCookie[CDP_SPECIFIC_PREFIX + property] !== undefined) { + result[property] = bidiCookie[CDP_SPECIFIC_PREFIX + property]; + } + } + return result; +} + +/** + * Gets CDP-specific properties from the cookie, adds CDP-specific prefixes and returns + * them as a new object which can be used in BiDi. + */ +function cdpSpecificCookiePropertiesFromPuppeteerToBidi( + cookieParam: CookieParam, + ...propertyNames: Array<keyof CookieParam> +): Record<string, unknown> { + const result: Record<string, unknown> = {}; + for (const property of propertyNames) { + if (cookieParam[property] !== undefined) { + result[CDP_SPECIFIC_PREFIX + property] = cookieParam[property]; + } + } + return result; +} + +function convertCookiesSameSiteBiDiToCdp( + sameSite: Bidi.Network.SameSite | undefined +): CookieSameSite { + return sameSite === 'strict' ? 'Strict' : sameSite === 'lax' ? 'Lax' : 'None'; +} + +function convertCookiesSameSiteCdpToBiDi( + sameSite: CookieSameSite | undefined +): Bidi.Network.SameSite { + return sameSite === 'Strict' + ? Bidi.Network.SameSite.Strict + : sameSite === 'Lax' + ? Bidi.Network.SameSite.Lax + : Bidi.Network.SameSite.None; } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Realm.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Realm.ts index 84f13bc703..1027941e2f 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Realm.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Realm.ts @@ -1,80 +1,63 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; -import {EventEmitter, type EventType} from '../common/EventEmitter.js'; +import type {JSHandle} from '../api/JSHandle.js'; +import {Realm} from '../api/Realm.js'; +import {ARIAQueryHandler} from '../cdp/AriaQueryHandler.js'; +import {LazyArg} from '../common/LazyArg.js'; import {scriptInjector} from '../common/ScriptInjector.js'; +import type {TimeoutSettings} from '../common/TimeoutSettings.js'; import type {EvaluateFunc, HandleFor} from '../common/types.js'; import { - PuppeteerURL, - SOURCE_URL_REGEX, + debugError, getSourcePuppeteerURLIfAvailable, getSourceUrlComment, isString, + PuppeteerURL, + SOURCE_URL_REGEX, } from '../common/util.js'; import type PuppeteerUtil from '../injected/injected.js'; -import {disposeSymbol} from '../util/disposable.js'; +import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js'; import {stringifyFunction} from '../util/Function.js'; -import type {BidiConnection} from './Connection.js'; +import type { + Realm as BidiRealmCore, + DedicatedWorkerRealm, + SharedWorkerRealm, +} from './core/Realm.js'; +import type {WindowRealm} from './core/Realm.js'; import {BidiDeserializer} from './Deserializer.js'; import {BidiElementHandle} from './ElementHandle.js'; +import {ExposeableFunction} from './ExposedFunction.js'; +import type {BidiFrame} from './Frame.js'; import {BidiJSHandle} from './JSHandle.js'; -import type {Sandbox} from './Sandbox.js'; import {BidiSerializer} from './Serializer.js'; import {createEvaluationError} from './util.js'; +import type {BidiWebWorker} from './WebWorker.js'; /** * @internal */ -export class BidiRealm extends EventEmitter<Record<EventType, any>> { - readonly connection: BidiConnection; - - #id!: string; - #sandbox!: Sandbox; +export abstract class BidiRealm extends Realm { + readonly realm: BidiRealmCore; - constructor(connection: BidiConnection) { - super(); - this.connection = connection; + constructor(realm: BidiRealmCore, timeoutSettings: TimeoutSettings) { + super(timeoutSettings); + this.realm = realm; } - get target(): Bidi.Script.Target { - return { - context: this.#sandbox.environment._id, - sandbox: this.#sandbox.name, - }; - } - - handleRealmDestroyed = async ( - params: Bidi.Script.RealmDestroyed['params'] - ): Promise<void> => { - if (params.realm === this.#id) { - // Note: The Realm is destroyed, so in theory the handle should be as - // well. + protected initialize(): void { + this.realm.on('destroyed', ({reason}) => { + this.taskManager.terminateAll(new Error(reason)); + }); + this.realm.on('updated', () => { this.internalPuppeteerUtil = undefined; - this.#sandbox.environment.clearDocumentHandle(); - } - }; - - handleRealmCreated = (params: Bidi.Script.RealmCreated['params']): void => { - if ( - params.type === 'window' && - params.context === this.#sandbox.environment._id && - params.sandbox === this.#sandbox.name - ) { - this.#id = params.realm; - void this.#sandbox.taskManager.rerunAll(); - } - }; - - setSandbox(sandbox: Sandbox): void { - this.#sandbox = sandbox; - this.connection.on( - Bidi.ChromiumBidi.Script.EventNames.RealmCreated, - this.handleRealmCreated - ); - this.connection.on( - Bidi.ChromiumBidi.Script.EventNames.RealmDestroyed, - this.handleRealmDestroyed - ); + void this.taskManager.rerunAll(); + }); } protected internalPuppeteerUtil?: Promise<BidiJSHandle<PuppeteerUtil>>; @@ -95,7 +78,7 @@ export class BidiRealm extends EventEmitter<Record<EventType, any>> { return this.internalPuppeteerUtil as Promise<BidiJSHandle<PuppeteerUtil>>; } - async evaluateHandle< + override async evaluateHandle< Params extends unknown[], Func extends EvaluateFunc<Params> = EvaluateFunc<Params>, >( @@ -105,7 +88,7 @@ export class BidiRealm extends EventEmitter<Record<EventType, any>> { return await this.#evaluate(false, pageFunction, ...args); } - async evaluate< + override async evaluate< Params extends unknown[], Func extends EvaluateFunc<Params> = EvaluateFunc<Params>, >( @@ -144,8 +127,6 @@ export class BidiRealm extends EventEmitter<Record<EventType, any>> { PuppeteerURL.INTERNAL_URL ); - const sandbox = this.#sandbox; - let responsePromise; const resultOwnership = returnByValue ? Bidi.Script.ResultOwnership.None @@ -161,11 +142,8 @@ export class BidiRealm extends EventEmitter<Record<EventType, any>> { ? pageFunction : `${pageFunction}\n${sourceUrlComment}\n`; - responsePromise = this.connection.send('script.evaluate', { - expression, - target: this.target, + responsePromise = this.realm.evaluate(expression, true, { resultOwnership, - awaitPromise: true, userActivation: true, serializationOptions, }); @@ -174,24 +152,25 @@ export class BidiRealm extends EventEmitter<Record<EventType, any>> { functionDeclaration = SOURCE_URL_REGEX.test(functionDeclaration) ? functionDeclaration : `${functionDeclaration}\n${sourceUrlComment}\n`; - responsePromise = this.connection.send('script.callFunction', { + responsePromise = this.realm.callFunction( functionDeclaration, - arguments: args.length - ? await Promise.all( - args.map(arg => { - return BidiSerializer.serialize(sandbox, arg); - }) - ) - : [], - target: this.target, - resultOwnership, - awaitPromise: true, - userActivation: true, - serializationOptions, - }); + /* awaitPromise= */ true, + { + arguments: args.length + ? await Promise.all( + args.map(arg => { + return this.serialize(arg); + }) + ) + : [], + resultOwnership, + userActivation: true, + serializationOptions, + } + ); } - const {result} = await responsePromise; + const result = await responsePromise; if ('type' in result && result.type === 'exception') { throw createEvaluationError(result.exceptionDetails); @@ -199,30 +178,211 @@ export class BidiRealm extends EventEmitter<Record<EventType, any>> { return returnByValue ? BidiDeserializer.deserialize(result.result) - : createBidiHandle(sandbox, result.result); + : this.createHandle(result.result); } - [disposeSymbol](): void { - this.connection.off( - Bidi.ChromiumBidi.Script.EventNames.RealmCreated, - this.handleRealmCreated - ); - this.connection.off( - Bidi.ChromiumBidi.Script.EventNames.RealmDestroyed, - this.handleRealmDestroyed + createHandle( + result: Bidi.Script.RemoteValue + ): BidiJSHandle<unknown> | BidiElementHandle<Node> { + if ( + (result.type === 'node' || result.type === 'window') && + this instanceof BidiFrameRealm + ) { + return BidiElementHandle.from(result, this); + } + return BidiJSHandle.from(result, this); + } + + async serialize(arg: unknown): Promise<Bidi.Script.LocalValue> { + if (arg instanceof LazyArg) { + arg = await arg.get(this); + } + + if (arg instanceof BidiJSHandle || arg instanceof BidiElementHandle) { + if (arg.realm !== this) { + if ( + !(arg.realm instanceof BidiFrameRealm) || + !(this instanceof BidiFrameRealm) + ) { + throw new Error( + "Trying to evaluate JSHandle from different global types. Usually this means you're using a handle from a worker in a page or vice versa." + ); + } + if (arg.realm.environment !== this.environment) { + throw new Error( + "Trying to evaluate JSHandle from different frames. Usually this means you're using a handle from a page on a different page." + ); + } + } + if (arg.disposed) { + throw new Error('JSHandle is disposed!'); + } + return arg.remoteValue() as Bidi.Script.RemoteReference; + } + + return BidiSerializer.serialize(arg); + } + + async destroyHandles(handles: Array<BidiJSHandle<unknown>>): Promise<void> { + const handleIds = handles + .map(({id}) => { + return id; + }) + .filter((id): id is string => { + return id !== undefined; + }); + + if (handleIds.length === 0) { + return; + } + + await this.realm.disown(handleIds).catch(error => { + // Exceptions might happen in case of a page been navigated or closed. + // Swallow these since they are harmless and we don't leak anything in this case. + debugError(error); + }); + } + + override async adoptHandle<T extends JSHandle<Node>>(handle: T): Promise<T> { + return (await this.evaluateHandle(node => { + return node; + }, handle)) as unknown as T; + } + + override async transferHandle<T extends JSHandle<Node>>( + handle: T + ): Promise<T> { + if (handle.realm === this) { + return handle; + } + const transferredHandle = this.adoptHandle(handle); + await handle.dispose(); + return await transferredHandle; + } +} + +/** + * @internal + */ +export class BidiFrameRealm extends BidiRealm { + static from(realm: WindowRealm, frame: BidiFrame): BidiFrameRealm { + const frameRealm = new BidiFrameRealm(realm, frame); + frameRealm.#initialize(); + return frameRealm; + } + declare readonly realm: WindowRealm; + + readonly #frame: BidiFrame; + + private constructor(realm: WindowRealm, frame: BidiFrame) { + super(realm, frame.timeoutSettings); + this.#frame = frame; + } + + #initialize() { + super.initialize(); + + // This should run first. + this.realm.on('updated', () => { + this.environment.clearDocumentHandle(); + this.#bindingsInstalled = false; + }); + } + + #bindingsInstalled = false; + override get puppeteerUtil(): Promise<BidiJSHandle<PuppeteerUtil>> { + let promise = Promise.resolve() as Promise<unknown>; + if (!this.#bindingsInstalled) { + promise = Promise.all([ + ExposeableFunction.from( + this.environment as BidiFrame, + '__ariaQuerySelector', + ARIAQueryHandler.queryOne, + !!this.sandbox + ), + ExposeableFunction.from( + this.environment as BidiFrame, + '__ariaQuerySelectorAll', + async ( + element: BidiElementHandle<Node>, + selector: string + ): Promise<JSHandle<Node[]>> => { + const results = ARIAQueryHandler.queryAll(element, selector); + return await element.realm.evaluateHandle( + (...elements) => { + return elements; + }, + ...(await AsyncIterableUtil.collect(results)) + ); + }, + !!this.sandbox + ), + ]); + this.#bindingsInstalled = true; + } + return promise.then(() => { + return super.puppeteerUtil; + }); + } + + get sandbox(): string | undefined { + return this.realm.sandbox; + } + + override get environment(): BidiFrame { + return this.#frame; + } + + override async adoptBackendNode( + backendNodeId?: number | undefined + ): Promise<JSHandle<Node>> { + const {object} = await this.#frame.client.send('DOM.resolveNode', { + backendNodeId, + executionContextId: await this.realm.resolveExecutionContextId(), + }); + using handle = BidiElementHandle.from( + { + handle: object.objectId, + type: 'node', + }, + this ); + // We need the sharedId, so we perform the following to obtain it. + return await handle.evaluateHandle(element => { + return element; + }); } } /** * @internal */ -export function createBidiHandle( - sandbox: Sandbox, - result: Bidi.Script.RemoteValue -): BidiJSHandle<unknown> | BidiElementHandle<Node> { - if (result.type === 'node' || result.type === 'window') { - return new BidiElementHandle(sandbox, result); - } - return new BidiJSHandle(sandbox, result); +export class BidiWorkerRealm extends BidiRealm { + static from( + realm: DedicatedWorkerRealm | SharedWorkerRealm, + worker: BidiWebWorker + ): BidiWorkerRealm { + const workerRealm = new BidiWorkerRealm(realm, worker); + workerRealm.initialize(); + return workerRealm; + } + declare readonly realm: DedicatedWorkerRealm | SharedWorkerRealm; + + readonly #worker: BidiWebWorker; + + private constructor( + realm: DedicatedWorkerRealm | SharedWorkerRealm, + frame: BidiWebWorker + ) { + super(realm, frame.timeoutSettings); + this.#worker = frame; + } + + override get environment(): BidiWebWorker { + return this.#worker; + } + + override async adoptBackendNode(): Promise<JSHandle<Node>> { + throw new Error('Cannot adopt DOM nodes into a worker.'); + } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Sandbox.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Sandbox.ts deleted file mode 100644 index 4411b3dbcd..0000000000 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Sandbox.ts +++ /dev/null @@ -1,123 +0,0 @@ -/** - * @license - * Copyright 2023 Google Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -import type {JSHandle} from '../api/JSHandle.js'; -import {Realm} from '../api/Realm.js'; -import type {TimeoutSettings} from '../common/TimeoutSettings.js'; -import type {EvaluateFunc, HandleFor} from '../common/types.js'; -import {withSourcePuppeteerURLIfNone} from '../common/util.js'; - -import type {BrowsingContext} from './BrowsingContext.js'; -import {BidiElementHandle} from './ElementHandle.js'; -import type {BidiFrame} from './Frame.js'; -import type {BidiRealm as BidiRealm} from './Realm.js'; -/** - * A unique key for {@link SandboxChart} to denote the default world. - * Realms are automatically created in the default sandbox. - * - * @internal - */ -export const MAIN_SANDBOX = Symbol('mainSandbox'); -/** - * A unique key for {@link SandboxChart} to denote the puppeteer sandbox. - * This world contains all puppeteer-internal bindings/code. - * - * @internal - */ -export const PUPPETEER_SANDBOX = Symbol('puppeteerSandbox'); - -/** - * @internal - */ -export interface SandboxChart { - [key: string]: Sandbox; - [MAIN_SANDBOX]: Sandbox; - [PUPPETEER_SANDBOX]: Sandbox; -} - -/** - * @internal - */ -export class Sandbox extends Realm { - readonly name: string | undefined; - readonly realm: BidiRealm; - #frame: BidiFrame; - - constructor( - name: string | undefined, - frame: BidiFrame, - // TODO: We should split the Realm and BrowsingContext - realm: BidiRealm | BrowsingContext, - timeoutSettings: TimeoutSettings - ) { - super(timeoutSettings); - this.name = name; - this.realm = realm; - this.#frame = frame; - this.realm.setSandbox(this); - } - - override get environment(): BidiFrame { - return this.#frame; - } - - async evaluateHandle< - Params extends unknown[], - Func extends EvaluateFunc<Params> = EvaluateFunc<Params>, - >( - pageFunction: Func | string, - ...args: Params - ): Promise<HandleFor<Awaited<ReturnType<Func>>>> { - pageFunction = withSourcePuppeteerURLIfNone( - this.evaluateHandle.name, - pageFunction - ); - return await this.realm.evaluateHandle(pageFunction, ...args); - } - - async evaluate< - Params extends unknown[], - Func extends EvaluateFunc<Params> = EvaluateFunc<Params>, - >( - pageFunction: Func | string, - ...args: Params - ): Promise<Awaited<ReturnType<Func>>> { - pageFunction = withSourcePuppeteerURLIfNone( - this.evaluate.name, - pageFunction - ); - return await this.realm.evaluate(pageFunction, ...args); - } - - async adoptHandle<T extends JSHandle<Node>>(handle: T): Promise<T> { - return (await this.evaluateHandle(node => { - return node; - }, handle)) as unknown as T; - } - - async transferHandle<T extends JSHandle<Node>>(handle: T): Promise<T> { - if (handle.realm === this) { - return handle; - } - const transferredHandle = await this.evaluateHandle(node => { - return node; - }, handle); - await handle.dispose(); - return transferredHandle as unknown as T; - } - - override async adoptBackendNode( - backendNodeId?: number - ): Promise<JSHandle<Node>> { - const {object} = await this.environment.client.send('DOM.resolveNode', { - backendNodeId: backendNodeId, - }); - return new BidiElementHandle(this, { - handle: object.objectId, - type: 'node', - }); - } -} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Serializer.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Serializer.ts index c147ec9281..523380782b 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Serializer.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Serializer.ts @@ -6,13 +6,8 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; -import {LazyArg} from '../common/LazyArg.js'; import {isDate, isPlainObject, isRegExp} from '../common/util.js'; -import {BidiElementHandle} from './ElementHandle.js'; -import {BidiJSHandle} from './JSHandle.js'; -import type {Sandbox} from './Sandbox.js'; - /** * @internal */ @@ -22,7 +17,39 @@ class UnserializableError extends Error {} * @internal */ export class BidiSerializer { - static serializeNumber(arg: number): Bidi.Script.LocalValue { + static serialize(arg: unknown): Bidi.Script.LocalValue { + switch (typeof arg) { + case 'symbol': + case 'function': + throw new UnserializableError(`Unable to serializable ${typeof arg}`); + case 'object': + return this.#serializeObject(arg); + + case 'undefined': + return { + type: 'undefined', + }; + case 'number': + return this.#serializeNumber(arg); + case 'bigint': + return { + type: 'bigint', + value: arg.toString(), + }; + case 'string': + return { + type: 'string', + value: arg, + }; + case 'boolean': + return { + type: 'boolean', + value: arg, + }; + } + } + + static #serializeNumber(arg: number): Bidi.Script.LocalValue { let value: Bidi.Script.SpecialNumber | number; if (Object.is(arg, -0)) { value = '-0'; @@ -41,14 +68,14 @@ export class BidiSerializer { }; } - static serializeObject(arg: object | null): Bidi.Script.LocalValue { + static #serializeObject(arg: object | null): Bidi.Script.LocalValue { if (arg === null) { return { type: 'null', }; } else if (Array.isArray(arg)) { const parsedArray = arg.map(subArg => { - return BidiSerializer.serializeRemoteValue(subArg); + return this.serialize(subArg); }); return { @@ -70,10 +97,7 @@ export class BidiSerializer { const parsedObject: Bidi.Script.MappingLocalValue = []; for (const key in arg) { - parsedObject.push([ - BidiSerializer.serializeRemoteValue(key), - BidiSerializer.serializeRemoteValue(arg[key]), - ]); + parsedObject.push([this.serialize(key), this.serialize(arg[key])]); } return { @@ -99,66 +123,4 @@ export class BidiSerializer { 'Custom object sterilization not possible. Use plain objects instead.' ); } - - static serializeRemoteValue(arg: unknown): Bidi.Script.LocalValue { - switch (typeof arg) { - case 'symbol': - case 'function': - throw new UnserializableError(`Unable to serializable ${typeof arg}`); - case 'object': - return BidiSerializer.serializeObject(arg); - - case 'undefined': - return { - type: 'undefined', - }; - case 'number': - return BidiSerializer.serializeNumber(arg); - case 'bigint': - return { - type: 'bigint', - value: arg.toString(), - }; - case 'string': - return { - type: 'string', - value: arg, - }; - case 'boolean': - return { - type: 'boolean', - value: arg, - }; - } - } - - static async serialize( - sandbox: Sandbox, - arg: unknown - ): Promise<Bidi.Script.LocalValue> { - if (arg instanceof LazyArg) { - arg = await arg.get(sandbox.realm); - } - // eslint-disable-next-line rulesdir/use-using -- We want this to continue living. - const objectHandle = - arg && (arg instanceof BidiJSHandle || arg instanceof BidiElementHandle) - ? arg - : null; - if (objectHandle) { - if ( - objectHandle.realm.environment.context() !== - sandbox.environment.context() - ) { - throw new Error( - 'JSHandles can be evaluated only in the context they were created!' - ); - } - if (objectHandle.disposed) { - throw new Error('JSHandle is disposed!'); - } - return objectHandle.remoteValue() as Bidi.Script.RemoteReference; - } - - return BidiSerializer.serializeRemoteValue(arg); - } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Target.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Target.ts index fb01c34638..b9d78538aa 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Target.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Target.ts @@ -4,48 +4,46 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {CDPSession} from '../api/CDPSession.js'; -import type {Page} from '../api/Page.js'; import {Target, TargetType} from '../api/Target.js'; import {UnsupportedOperation} from '../common/Errors.js'; +import type {CDPSession} from '../puppeteer-core.js'; import type {BidiBrowser} from './Browser.js'; import type {BidiBrowserContext} from './BrowserContext.js'; -import {type BrowsingContext, CdpSessionWrapper} from './BrowsingContext.js'; +import type {BidiFrame} from './Frame.js'; import {BidiPage} from './Page.js'; +import type {BidiWebWorker} from './WebWorker.js'; /** * @internal */ -export abstract class BidiTarget extends Target { - protected _browserContext: BidiBrowserContext; +export class BidiBrowserTarget extends Target { + #browser: BidiBrowser; - constructor(browserContext: BidiBrowserContext) { + constructor(browser: BidiBrowser) { super(); - this._browserContext = browserContext; + this.#browser = browser; } - _setBrowserContext(browserContext: BidiBrowserContext): void { - this._browserContext = browserContext; + override asPage(): Promise<BidiPage> { + throw new UnsupportedOperation(); } - - override asPage(): Promise<Page> { + override url(): string { + return ''; + } + override createCDPSession(): Promise<CDPSession> { throw new UnsupportedOperation(); } - + override type(): TargetType { + return TargetType.BROWSER; + } override browser(): BidiBrowser { - return this._browserContext.browser(); + return this.#browser; } - override browserContext(): BidiBrowserContext { - return this._browserContext; - } - - override opener(): never { - throw new UnsupportedOperation(); + return this.#browser.defaultBrowserContext(); } - - override createCDPSession(): Promise<CDPSession> { + override opener(): Target | undefined { throw new UnsupportedOperation(); } } @@ -53,39 +51,39 @@ export abstract class BidiTarget extends Target { /** * @internal */ -export class BiDiBrowserTarget extends Target { - #browser: BidiBrowser; +export class BidiPageTarget extends Target { + #page: BidiPage; - constructor(browser: BidiBrowser) { + constructor(page: BidiPage) { super(); - this.#browser = browser; + this.#page = page; } + override async page(): Promise<BidiPage> { + return this.#page; + } + override async asPage(): Promise<BidiPage> { + return BidiPage.from( + this.browserContext(), + this.#page.mainFrame().browsingContext + ); + } override url(): string { - return ''; + return this.#page.url(); } - - override type(): TargetType { - return TargetType.BROWSER; + override createCDPSession(): Promise<CDPSession> { + return this.#page.createCDPSession(); } - - override asPage(): Promise<Page> { - throw new UnsupportedOperation(); + override type(): TargetType { + return TargetType.PAGE; } - override browser(): BidiBrowser { - return this.#browser; + return this.browserContext().browser(); } - override browserContext(): BidiBrowserContext { - return this.#browser.defaultBrowserContext(); - } - - override opener(): never { - throw new UnsupportedOperation(); + return this.#page.browserContext(); } - - override createCDPSession(): Promise<CDPSession> { + override opener(): Target | undefined { throw new UnsupportedOperation(); } } @@ -93,59 +91,80 @@ export class BiDiBrowserTarget extends Target { /** * @internal */ -export class BiDiBrowsingContextTarget extends BidiTarget { - protected _browsingContext: BrowsingContext; +export class BidiFrameTarget extends Target { + #frame: BidiFrame; + #page: BidiPage | undefined; - constructor( - browserContext: BidiBrowserContext, - browsingContext: BrowsingContext - ) { - super(browserContext); - - this._browsingContext = browsingContext; + constructor(frame: BidiFrame) { + super(); + this.#frame = frame; } + override async page(): Promise<BidiPage> { + if (this.#page === undefined) { + this.#page = BidiPage.from( + this.browserContext(), + this.#frame.browsingContext + ); + } + return this.#page; + } + override async asPage(): Promise<BidiPage> { + return BidiPage.from(this.browserContext(), this.#frame.browsingContext); + } override url(): string { - return this._browsingContext.url; + return this.#frame.url(); } - - override async createCDPSession(): Promise<CDPSession> { - const {sessionId} = await this._browsingContext.cdpSession.send( - 'Target.attachToTarget', - { - targetId: this._browsingContext.id, - flatten: true, - } - ); - return new CdpSessionWrapper(this._browsingContext, sessionId); + override createCDPSession(): Promise<CDPSession> { + return this.#frame.createCDPSession(); } - override type(): TargetType { return TargetType.PAGE; } + override browser(): BidiBrowser { + return this.browserContext().browser(); + } + override browserContext(): BidiBrowserContext { + return this.#frame.page().browserContext(); + } + override opener(): Target | undefined { + throw new UnsupportedOperation(); + } } /** * @internal */ -export class BiDiPageTarget extends BiDiBrowsingContextTarget { - #page: BidiPage; - - constructor( - browserContext: BidiBrowserContext, - browsingContext: BrowsingContext - ) { - super(browserContext, browsingContext); +export class BidiWorkerTarget extends Target { + #worker: BidiWebWorker; - this.#page = new BidiPage(browsingContext, browserContext, this); + constructor(worker: BidiWebWorker) { + super(); + this.#worker = worker; } override async page(): Promise<BidiPage> { - return this.#page; + throw new UnsupportedOperation(); } - - override _setBrowserContext(browserContext: BidiBrowserContext): void { - super._setBrowserContext(browserContext); - this.#page._setBrowserContext(browserContext); + override async asPage(): Promise<BidiPage> { + throw new UnsupportedOperation(); + } + override url(): string { + return this.#worker.url(); + } + override createCDPSession(): Promise<CDPSession> { + throw new UnsupportedOperation(); + } + override type(): TargetType { + return TargetType.OTHER; + } + override browser(): BidiBrowser { + return this.browserContext().browser(); + } + override browserContext(): BidiBrowserContext { + return this.#worker.frame.page().browserContext(); + } + override opener(): Target | undefined { + throw new UnsupportedOperation(); } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/WebWorker.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/WebWorker.ts new file mode 100644 index 0000000000..a8b0e28846 --- /dev/null +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/WebWorker.ts @@ -0,0 +1,48 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +import {WebWorker} from '../api/WebWorker.js'; +import {UnsupportedOperation} from '../common/Errors.js'; +import type {CDPSession} from '../puppeteer-core.js'; + +import type {DedicatedWorkerRealm, SharedWorkerRealm} from './core/Realm.js'; +import type {BidiFrame} from './Frame.js'; +import {BidiWorkerRealm} from './Realm.js'; + +/** + * @internal + */ +export class BidiWebWorker extends WebWorker { + static from( + frame: BidiFrame, + realm: DedicatedWorkerRealm | SharedWorkerRealm + ): BidiWebWorker { + const worker = new BidiWebWorker(frame, realm); + return worker; + } + + readonly #frame: BidiFrame; + readonly #realm: BidiWorkerRealm; + private constructor( + frame: BidiFrame, + realm: DedicatedWorkerRealm | SharedWorkerRealm + ) { + super(realm.origin); + this.#frame = frame; + this.#realm = BidiWorkerRealm.from(realm, this); + } + + get frame(): BidiFrame { + return this.#frame; + } + + mainRealm(): BidiWorkerRealm { + return this.#realm; + } + + get client(): CDPSession { + throw new UnsupportedOperation(); + } +} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/bidi.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/bidi.ts index 373d6d999c..4279ba96fd 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/bidi.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/bidi.ts @@ -7,7 +7,6 @@ export * from './BidiOverCdp.js'; export * from './Browser.js'; export * from './BrowserContext.js'; -export * from './BrowsingContext.js'; export * from './Connection.js'; export * from './ElementHandle.js'; export * from './Frame.js'; @@ -15,8 +14,5 @@ export * from './HTTPRequest.js'; export * from './HTTPResponse.js'; export * from './Input.js'; export * from './JSHandle.js'; -export * from './NetworkManager.js'; export * from './Page.js'; export * from './Realm.js'; -export * from './Sandbox.js'; -export * from './Target.js'; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Browser.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Browser.ts index 7c4a8ed01c..efeabc3a59 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Browser.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Browser.ts @@ -11,7 +11,7 @@ import {inertIfDisposed, throwIfDisposed} from '../../util/decorators.js'; import {DisposableStack, disposeSymbol} from '../../util/disposable.js'; import type {BrowsingContext} from './BrowsingContext.js'; -import type {SharedWorkerRealm} from './Realm.js'; +import {SharedWorkerRealm} from './Realm.js'; import type {Session} from './Session.js'; import {UserContext} from './UserContext.js'; @@ -57,6 +57,7 @@ export class Browser extends EventEmitter<{ readonly #disposables = new DisposableStack(); readonly #userContexts = new Map<string, UserContext>(); readonly session: Session; + readonly #sharedWorkers = new Map<string, SharedWorkerRealm>(); // keep-sorted end private constructor(session: Session) { @@ -64,11 +65,6 @@ export class Browser extends EventEmitter<{ // keep-sorted start this.session = session; // keep-sorted end - - this.#userContexts.set( - UserContext.DEFAULT, - UserContext.create(this, UserContext.DEFAULT) - ); } async #initialize() { @@ -80,14 +76,29 @@ export class Browser extends EventEmitter<{ }); sessionEmitter.on('script.realmCreated', info => { - if (info.type === 'shared-worker') { - // TODO: Create a SharedWorkerRealm. + if (info.type !== 'shared-worker') { + return; } + this.#sharedWorkers.set( + info.realm, + SharedWorkerRealm.from(this, info.realm, info.origin) + ); }); + await this.#syncUserContexts(); await this.#syncBrowsingContexts(); } + async #syncUserContexts() { + const { + result: {userContexts}, + } = await this.session.send('browser.getUserContexts', {}); + + for (const context of userContexts) { + this.#createUserContext(context.userContext); + } + } + async #syncBrowsingContexts() { // In case contexts are created or destroyed during `getTree`, we use this // set to detect them. @@ -99,16 +110,13 @@ export class Browser extends EventEmitter<{ sessionEmitter.on('browsingContext.contextCreated', info => { contextIds.add(info.context); }); - sessionEmitter.on('browsingContext.contextDestroyed', info => { - contextIds.delete(info.context); - }); const {result} = await this.session.send('browsingContext.getTree', {}); contexts = result.contexts; } // Simulating events so contexts are created naturally. for (const info of contexts) { - if (contextIds.has(info.context)) { + if (!contextIds.has(info.context)) { this.session.emit('browsingContext.contextCreated', info); } if (info.children) { @@ -117,6 +125,22 @@ export class Browser extends EventEmitter<{ } } + #createUserContext(id: string) { + const userContext = UserContext.create(this, id); + this.#userContexts.set(userContext.id, userContext); + + const userContextEmitter = this.#disposables.use( + new EventEmitter(userContext) + ); + userContextEmitter.once('closed', () => { + userContextEmitter.removeAllListeners(); + + this.#userContexts.delete(userContext.id); + }); + + return userContext; + } + // keep-sorted start block=yes get closed(): boolean { return this.#closed; @@ -185,30 +209,15 @@ export class Browser extends EventEmitter<{ }); } - static userContextId = 0; @throwIfDisposed<Browser>(browser => { // SAFETY: By definition of `disposed`, `#reason` is defined. return browser.#reason!; }) async createUserContext(): Promise<UserContext> { - // TODO: implement incognito context https://github.com/w3c/webdriver-bidi/issues/289. - // TODO: Call `createUserContext` once available. - // Generating a monotonically increasing context id. - const context = `${++Browser.userContextId}`; - - const userContext = UserContext.create(this, context); - this.#userContexts.set(userContext.id, userContext); - - const userContextEmitter = this.#disposables.use( - new EventEmitter(userContext) - ); - userContextEmitter.once('closed', () => { - userContextEmitter.removeAllListeners(); - - this.#userContexts.delete(context); - }); - - return userContext; + const { + result: {userContext: context}, + } = await this.session.send('browser.createUserContext', {}); + return this.#createUserContext(context); } [disposeSymbol](): void { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/BrowsingContext.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/BrowsingContext.ts index 9bec2a506c..07309576a3 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/BrowsingContext.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/BrowsingContext.ts @@ -12,6 +12,7 @@ import {DisposableStack, disposeSymbol} from '../../util/disposable.js'; import type {AddPreloadScriptOptions} from './Browser.js'; import {Navigation} from './Navigation.js'; +import type {DedicatedWorkerRealm} from './Realm.js'; import {WindowRealm} from './Realm.js'; import {Request} from './Request.js'; import type {UserContext} from './UserContext.js'; @@ -60,6 +61,14 @@ export type SetViewportOptions = Omit< /** * @internal */ +export type GetCookiesOptions = Omit< + Bidi.Storage.GetCookiesParameters, + 'partition' +>; + +/** + * @internal + */ export class BrowsingContext extends EventEmitter<{ /** Emitted when this context is closed. */ closed: { @@ -95,6 +104,11 @@ export class BrowsingContext extends EventEmitter<{ DOMContentLoaded: void; /** Emitted whenever the frame emits `load` */ load: void; + /** Emitted whenever a dedicated worker is created */ + worker: { + /** The realm for the new dedicated worker */ + realm: DedicatedWorkerRealm; + }; }> { static from( userContext: UserContext, @@ -135,7 +149,7 @@ export class BrowsingContext extends EventEmitter<{ this.userContext = context; // keep-sorted end - this.defaultRealm = WindowRealm.from(this); + this.defaultRealm = this.#createWindowRealm(); } #initialize() { @@ -202,7 +216,16 @@ export class BrowsingContext extends EventEmitter<{ } this.#url = info.url; - this.#requests.clear(); + for (const [id, request] of this.#requests) { + if (request.disposed) { + this.#requests.delete(id); + } + } + // If the navigation hasn't finished, then this is nested navigation. The + // current navigation will handle this. + if (this.#navigation !== undefined && !this.#navigation.disposed) { + return; + } // Note the navigation ID is null for this event. this.#navigation = Navigation.from(this); @@ -224,7 +247,8 @@ export class BrowsingContext extends EventEmitter<{ if (event.context !== this.id) { return; } - if (this.#requests.has(event.request.request)) { + if (event.redirectCount !== 0) { + // Means the request is a redirect. This is handled in Request. return; } @@ -265,7 +289,12 @@ export class BrowsingContext extends EventEmitter<{ return this.closed; } get realms(): Iterable<WindowRealm> { - return this.#realms.values(); + // eslint-disable-next-line @typescript-eslint/no-this-alias -- Required + const self = this; + return (function* () { + yield self.defaultRealm; + yield* self.#realms.values(); + })(); } get top(): BrowsingContext { let context = this as BrowsingContext; @@ -279,6 +308,14 @@ export class BrowsingContext extends EventEmitter<{ } // keep-sorted end + #createWindowRealm(sandbox?: string) { + const realm = WindowRealm.from(this, sandbox); + realm.on('worker', realm => { + this.emit('worker', {realm}); + }); + return realm; + } + @inertIfDisposed private dispose(reason?: string): void { this.#reason = reason; @@ -345,33 +382,23 @@ export class BrowsingContext extends EventEmitter<{ async navigate( url: string, wait?: Bidi.BrowsingContext.ReadinessState - ): Promise<Navigation> { + ): Promise<void> { await this.#session.send('browsingContext.navigate', { context: this.id, url, wait, }); - return await new Promise(resolve => { - this.once('navigation', ({navigation}) => { - resolve(navigation); - }); - }); } @throwIfDisposed<BrowsingContext>(context => { // SAFETY: Disposal implies this exists. return context.#reason!; }) - async reload(options: ReloadOptions = {}): Promise<Navigation> { + async reload(options: ReloadOptions = {}): Promise<void> { await this.#session.send('browsingContext.reload', { context: this.id, ...options, }); - return await new Promise(resolve => { - this.once('navigation', ({navigation}) => { - resolve(navigation); - }); - }); } @throwIfDisposed<BrowsingContext>(context => { @@ -436,7 +463,7 @@ export class BrowsingContext extends EventEmitter<{ return context.#reason!; }) createWindowRealm(sandbox: string): WindowRealm { - return WindowRealm.from(this, sandbox); + return this.#createWindowRealm(sandbox); } @throwIfDisposed<BrowsingContext>(context => { @@ -464,6 +491,54 @@ export class BrowsingContext extends EventEmitter<{ await this.userContext.browser.removePreloadScript(script); } + @throwIfDisposed<BrowsingContext>(context => { + // SAFETY: Disposal implies this exists. + return context.#reason!; + }) + async getCookies( + options: GetCookiesOptions = {} + ): Promise<Bidi.Network.Cookie[]> { + const { + result: {cookies}, + } = await this.#session.send('storage.getCookies', { + ...options, + partition: { + type: 'context', + context: this.id, + }, + }); + return cookies; + } + + @throwIfDisposed<BrowsingContext>(context => { + // SAFETY: Disposal implies this exists. + return context.#reason!; + }) + async setCookie(cookie: Bidi.Storage.PartialCookie): Promise<void> { + await this.#session.send('storage.setCookie', { + cookie, + partition: { + type: 'context', + context: this.id, + }, + }); + } + + @throwIfDisposed<BrowsingContext>(context => { + // SAFETY: Disposal implies this exists. + return context.#reason!; + }) + async setFiles( + element: Bidi.Script.SharedReference, + files: string[] + ): Promise<void> { + await this.#session.send('input.setFiles', { + context: this.id, + element, + files, + }); + } + [disposeSymbol](): void { this.#reason ??= 'Browsing context already closed, probably because the user context closed.'; @@ -472,4 +547,24 @@ export class BrowsingContext extends EventEmitter<{ this.#disposables.dispose(); super[disposeSymbol](); } + + @throwIfDisposed<BrowsingContext>(context => { + // SAFETY: Disposal implies this exists. + return context.#reason!; + }) + async deleteCookie( + ...cookieFilters: Bidi.Storage.CookieFilter[] + ): Promise<void> { + await Promise.all( + cookieFilters.map(async filter => { + await this.#session.send('storage.deleteCookies', { + filter: filter, + partition: { + type: 'context', + context: this.id, + }, + }); + }) + ); + } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Connection.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Connection.ts index b9de14372b..9c26a03503 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Connection.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Connection.ts @@ -38,6 +38,21 @@ export interface Commands { returnType: Bidi.EmptyResult; }; + 'browser.createUserContext': { + params: Bidi.EmptyParams; + returnType: Bidi.Browser.CreateUserContextResult; + }; + 'browser.getUserContexts': { + params: Bidi.EmptyParams; + returnType: Bidi.Browser.GetUserContextsResult; + }; + 'browser.removeUserContext': { + params: { + userContext: Bidi.Browser.UserContext; + }; + returnType: Bidi.Browser.RemoveUserContext; + }; + 'browsingContext.activate': { params: Bidi.BrowsingContext.ActivateParameters; returnType: Bidi.EmptyResult; @@ -91,6 +106,15 @@ export interface Commands { params: Bidi.Input.ReleaseActionsParameters; returnType: Bidi.EmptyResult; }; + 'input.setFiles': { + params: Bidi.Input.SetFilesParameters; + returnType: Bidi.EmptyResult; + }; + + 'permissions.setPermission': { + params: Bidi.Permissions.SetPermissionParameters; + returnType: Bidi.EmptyResult; + }; 'session.end': { params: Bidi.EmptyParams; @@ -112,6 +136,19 @@ export interface Commands { params: Bidi.Session.SubscriptionRequest; returnType: Bidi.EmptyResult; }; + + 'storage.deleteCookies': { + params: Bidi.Storage.DeleteCookiesParameters; + returnType: Bidi.Storage.DeleteCookiesResult; + }; + 'storage.getCookies': { + params: Bidi.Storage.GetCookiesParameters; + returnType: Bidi.Storage.GetCookiesResult; + }; + 'storage.setCookie': { + params: Bidi.Storage.SetCookieParameters; + returnType: Bidi.Storage.SetCookieParameters; + }; } /** @@ -133,7 +170,4 @@ export interface Connection<Events extends BidiEvents = BidiEvents> method: T, params: Commands[T]['params'] ): Promise<{result: Commands[T]['returnType']}>; - - // This will pipe events into the provided emitter. - pipeTo<Events extends BidiEvents>(emitter: EventEmitter<Events>): void; } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Navigation.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Navigation.ts index a7efbfeb2c..50040164a5 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Navigation.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Navigation.ts @@ -41,9 +41,10 @@ export class Navigation extends EventEmitter<{ // keep-sorted start #request: Request | undefined; + #navigation: Navigation | undefined; readonly #browsingContext: BrowsingContext; readonly #disposables = new DisposableStack(); - readonly #id = new Deferred<string>(); + readonly #id = new Deferred<string | null>(); // keep-sorted end private constructor(context: BrowsingContext) { @@ -65,31 +66,48 @@ export class Navigation extends EventEmitter<{ this.dispose(); }); - this.#browsingContext.on('request', ({request}) => { - if (request.navigation === this.#id.value()) { - this.#request = request; - this.emit('request', request); + browsingContextEmitter.on('request', ({request}) => { + if ( + request.navigation === undefined || + this.#request !== undefined || + // If a request with a navigation ID comes in, then the navigation ID is + // for this navigation. + !this.#matches(request.navigation) + ) { + return; } + + this.#request = request; + this.emit('request', request); }); const sessionEmitter = this.#disposables.use( new EventEmitter(this.#session) ); - // To get the navigation ID if any. + sessionEmitter.on('browsingContext.navigationStarted', info => { + if ( + info.context !== this.#browsingContext.id || + this.#navigation !== undefined + ) { + return; + } + this.#navigation = Navigation.from(this.#browsingContext); + }); + for (const eventName of [ 'browsingContext.domContentLoaded', 'browsingContext.load', ] as const) { sessionEmitter.on(eventName, info => { - if (info.context !== this.#browsingContext.id) { - return; - } - if (!info.navigation) { + if ( + info.context !== this.#browsingContext.id || + info.navigation === null || + !this.#matches(info.navigation) + ) { return; } - if (!this.#id.resolved()) { - this.#id.resolve(info.navigation); - } + + this.dispose(); }); } @@ -99,18 +117,15 @@ export class Navigation extends EventEmitter<{ ['browsingContext.navigationAborted', 'aborted'], ] as const) { sessionEmitter.on(eventName, info => { - if (info.context !== this.#browsingContext.id) { - return; - } - if (!info.navigation) { - return; - } - if (!this.#id.resolved()) { - this.#id.resolve(info.navigation); - } - if (this.#id.value() !== info.navigation) { + if ( + info.context !== this.#browsingContext.id || + // Note we don't check if `navigation` is null since `null` means the + // fragment navigated. + !this.#matches(info.navigation) + ) { return; } + this.emit(event, { url: info.url, timestamp: new Date(info.timestamp), @@ -120,6 +135,17 @@ export class Navigation extends EventEmitter<{ } } + #matches(navigation: string | null): boolean { + if (this.#navigation !== undefined && !this.#navigation.disposed) { + return false; + } + if (!this.#id.resolved()) { + this.#id.resolve(navigation); + return true; + } + return this.#id.value() === navigation; + } + // keep-sorted start block=yes get #session() { return this.#browsingContext.userContext.browser.session; @@ -130,6 +156,9 @@ export class Navigation extends EventEmitter<{ get request(): Request | undefined { return this.#request; } + get navigation(): Navigation | undefined { + return this.#navigation; + } // keep-sorted end @inertIfDisposed diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Realm.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Realm.ts index d9bbbede50..392194cec8 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Realm.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Realm.ts @@ -9,7 +9,9 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; import {EventEmitter} from '../../common/EventEmitter.js'; import {inertIfDisposed, throwIfDisposed} from '../../util/decorators.js'; import {DisposableStack, disposeSymbol} from '../../util/disposable.js'; +import type {BidiConnection} from '../Connection.js'; +import type {Browser} from './Browser.js'; import type {BrowsingContext} from './BrowsingContext.js'; import type {Session} from './Session.js'; @@ -33,6 +35,8 @@ export type EvaluateOptions = Omit< * @internal */ export abstract class Realm extends EventEmitter<{ + /** Emitted whenever the realm has updated. */ + updated: Realm; /** Emitted when the realm is destroyed. */ destroyed: {reason: string}; /** Emitted when a dedicated worker is created in the realm. */ @@ -55,22 +59,12 @@ export abstract class Realm extends EventEmitter<{ // keep-sorted end } - protected initialize(): void { - const sessionEmitter = this.disposables.use(new EventEmitter(this.session)); - sessionEmitter.on('script.realmDestroyed', info => { - if (info.realm !== this.id) { - return; - } - this.dispose('Realm already destroyed.'); - }); - } - // keep-sorted start block=yes get disposed(): boolean { return this.#reason !== undefined; } protected abstract get session(): Session; - protected get target(): Bidi.Script.Target { + get target(): Bidi.Script.Target { return {realm: this.id}; } // keep-sorted end @@ -128,6 +122,18 @@ export abstract class Realm extends EventEmitter<{ return result; } + @throwIfDisposed<Realm>(realm => { + // SAFETY: Disposal implies this exists. + return realm.#reason!; + }) + async resolveExecutionContextId(): Promise<number> { + const {result} = await (this.session.connection as BidiConnection).send( + 'cdp.resolveRealm', + {realm: this.id} + ); + return result.executionContextId; + } + [disposeSymbol](): void { this.#reason ??= 'Realm already destroyed, probably because all associated browsing contexts closed.'; @@ -144,7 +150,7 @@ export abstract class Realm extends EventEmitter<{ export class WindowRealm extends Realm { static from(context: BrowsingContext, sandbox?: string): WindowRealm { const realm = new WindowRealm(context, sandbox); - realm.initialize(); + realm.#initialize(); return realm; } @@ -153,13 +159,7 @@ export class WindowRealm extends Realm { readonly sandbox?: string; // keep-sorted end - readonly #workers: { - dedicated: Map<string, DedicatedWorkerRealm>; - shared: Map<string, SharedWorkerRealm>; - } = { - dedicated: new Map(), - shared: new Map(), - }; + readonly #workers = new Map<string, DedicatedWorkerRealm>(); private constructor(context: BrowsingContext, sandbox?: string) { super('', ''); @@ -169,16 +169,26 @@ export class WindowRealm extends Realm { // keep-sorted end } - override initialize(): void { - super.initialize(); + #initialize(): void { + const browsingContextEmitter = this.disposables.use( + new EventEmitter(this.browsingContext) + ); + browsingContextEmitter.on('closed', ({reason}) => { + this.dispose(reason); + }); const sessionEmitter = this.disposables.use(new EventEmitter(this.session)); sessionEmitter.on('script.realmCreated', info => { - if (info.type !== 'window') { + if ( + info.type !== 'window' || + info.context !== this.browsingContext.id || + info.sandbox !== this.sandbox + ) { return; } (this as any).id = info.realm; (this as any).origin = info.origin; + this.emit('updated', this); }); sessionEmitter.on('script.realmCreated', info => { if (info.type !== 'dedicated-worker') { @@ -189,32 +199,16 @@ export class WindowRealm extends Realm { } const realm = DedicatedWorkerRealm.from(this, info.realm, info.origin); - this.#workers.dedicated.set(realm.id, realm); + this.#workers.set(realm.id, realm); const realmEmitter = this.disposables.use(new EventEmitter(realm)); realmEmitter.once('destroyed', () => { realmEmitter.removeAllListeners(); - this.#workers.dedicated.delete(realm.id); + this.#workers.delete(realm.id); }); this.emit('worker', realm); }); - - this.browsingContext.userContext.browser.on('sharedworker', ({realm}) => { - if (!realm.owners.has(this)) { - return; - } - - this.#workers.shared.set(realm.id, realm); - - const realmEmitter = this.disposables.use(new EventEmitter(realm)); - realmEmitter.once('destroyed', () => { - realmEmitter.removeAllListeners(); - this.#workers.shared.delete(realm.id); - }); - - this.emit('sharedworker', realm); - }); } override get session(): Session { @@ -244,7 +238,7 @@ export class DedicatedWorkerRealm extends Realm { origin: string ): DedicatedWorkerRealm { const realm = new DedicatedWorkerRealm(owner, id, origin); - realm.initialize(); + realm.#initialize(); return realm; } @@ -262,10 +256,14 @@ export class DedicatedWorkerRealm extends Realm { this.owners = new Set([owner]); } - override initialize(): void { - super.initialize(); - + #initialize(): void { const sessionEmitter = this.disposables.use(new EventEmitter(this.session)); + sessionEmitter.on('script.realmDestroyed', info => { + if (info.realm !== this.id) { + return; + } + this.dispose('Realm already destroyed.'); + }); sessionEmitter.on('script.realmCreated', info => { if (info.type !== 'dedicated-worker') { return; @@ -296,34 +294,30 @@ export class DedicatedWorkerRealm extends Realm { * @internal */ export class SharedWorkerRealm extends Realm { - static from( - owners: [WindowRealm, ...WindowRealm[]], - id: string, - origin: string - ): SharedWorkerRealm { - const realm = new SharedWorkerRealm(owners, id, origin); - realm.initialize(); + static from(browser: Browser, id: string, origin: string): SharedWorkerRealm { + const realm = new SharedWorkerRealm(browser, id, origin); + realm.#initialize(); return realm; } // keep-sorted start readonly #workers = new Map<string, DedicatedWorkerRealm>(); - readonly owners: Set<WindowRealm>; + readonly browser: Browser; // keep-sorted end - private constructor( - owners: [WindowRealm, ...WindowRealm[]], - id: string, - origin: string - ) { + private constructor(browser: Browser, id: string, origin: string) { super(id, origin); - this.owners = new Set(owners); + this.browser = browser; } - override initialize(): void { - super.initialize(); - + #initialize(): void { const sessionEmitter = this.disposables.use(new EventEmitter(this.session)); + sessionEmitter.on('script.realmDestroyed', info => { + if (info.realm !== this.id) { + return; + } + this.dispose('Realm already destroyed.'); + }); sessionEmitter.on('script.realmCreated', info => { if (info.type !== 'dedicated-worker') { return; @@ -345,7 +339,6 @@ export class SharedWorkerRealm extends Realm { } override get session(): Session { - // SAFETY: At least one owner will exist. - return this.owners.values().next().value.session; + return this.browser.session; } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Request.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Request.ts index 2a445f7d87..fd616b668d 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Request.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Request.ts @@ -66,10 +66,11 @@ export class Request extends EventEmitter<{ new EventEmitter(this.#session) ); sessionEmitter.on('network.beforeRequestSent', event => { - if (event.context !== this.#browsingContext.id) { - return; - } - if (event.request.request !== this.id) { + if ( + event.context !== this.#browsingContext.id || + event.request.request !== this.id || + event.redirectCount !== this.#event.redirectCount + 1 + ) { return; } this.#redirect = Request.from(this.#browsingContext, event); @@ -77,10 +78,11 @@ export class Request extends EventEmitter<{ this.dispose(); }); sessionEmitter.on('network.fetchError', event => { - if (event.context !== this.#browsingContext.id) { - return; - } - if (event.request.request !== this.id) { + if ( + event.context !== this.#browsingContext.id || + event.request.request !== this.id || + this.#event.redirectCount !== event.redirectCount + ) { return; } this.#error = event.errorText; @@ -88,14 +90,19 @@ export class Request extends EventEmitter<{ this.dispose(); }); sessionEmitter.on('network.responseCompleted', event => { - if (event.context !== this.#browsingContext.id) { - return; - } - if (event.request.request !== this.id) { + if ( + event.context !== this.#browsingContext.id || + event.request.request !== this.id || + this.#event.redirectCount !== event.redirectCount + ) { return; } this.#response = event.response; this.emit('success', this.#response); + // In case this is a redirect. + if (this.#response.status >= 300 && this.#response.status < 400) { + return; + } this.dispose(); }); } @@ -126,7 +133,7 @@ export class Request extends EventEmitter<{ return this.#event.navigation ?? undefined; } get redirect(): Request | undefined { - return this.redirect; + return this.#redirect; } get response(): Bidi.Network.ResponseData | undefined { return this.#response; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Session.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Session.ts index b6e28061f1..ffd39769e7 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Session.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Session.ts @@ -8,7 +8,11 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; import {EventEmitter} from '../../common/EventEmitter.js'; import {debugError} from '../../common/util.js'; -import {inertIfDisposed, throwIfDisposed} from '../../util/decorators.js'; +import { + bubble, + inertIfDisposed, + throwIfDisposed, +} from '../../util/decorators.js'; import {DisposableStack, disposeSymbol} from '../../util/disposable.js'; import {Browser} from './Browser.js'; @@ -81,7 +85,8 @@ export class Session readonly #disposables = new DisposableStack(); readonly #info: Bidi.Session.NewResult; readonly browser!: Browser; - readonly connection: Connection; + @bubble() + accessor connection: Connection; // keep-sorted end private constructor(connection: Connection, info: Bidi.Session.NewResult) { @@ -93,8 +98,6 @@ export class Session } async #initialize(): Promise<void> { - this.connection.pipeTo(this); - // SAFETY: We use `any` to allow assignment of the readonly property. (this as any).browser = await Browser.from(this); @@ -102,6 +105,19 @@ export class Session browserEmitter.once('closed', ({reason}) => { this.dispose(reason); }); + + // TODO: Currently, some implementations do not emit navigationStarted event + // for fragment navigations (as per spec) and some do. This could emits a + // synthetic navigationStarted to work around this inconsistency. + const seen = new WeakSet(); + this.on('browsingContext.fragmentNavigated', info => { + if (seen.has(info)) { + return; + } + seen.add(info); + this.emit('browsingContext.navigationStarted', info); + this.emit('browsingContext.fragmentNavigated', info); + }); } // keep-sorted start block=yes @@ -125,10 +141,6 @@ export class Session this[disposeSymbol](); } - pipeTo<Events extends BidiEvents>(emitter: EventEmitter<Events>): void { - this.connection.pipeTo(emitter); - } - /** * Currently, there is a 1:1 relationship between the session and the * session. In the future, we might support multiple sessions and in that diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/UserContext.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/UserContext.ts index 01ee5c7649..72859c6a53 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/UserContext.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/UserContext.ts @@ -12,6 +12,7 @@ import {inertIfDisposed, throwIfDisposed} from '../../util/decorators.js'; import {DisposableStack, disposeSymbol} from '../../util/disposable.js'; import type {Browser} from './Browser.js'; +import type {GetCookiesOptions} from './BrowsingContext.js'; import {BrowsingContext} from './BrowsingContext.js'; /** @@ -43,7 +44,7 @@ export class UserContext extends EventEmitter<{ reason: string; }; }> { - static DEFAULT = 'default'; + static DEFAULT = 'default' as const; static create(browser: Browser, id: string): UserContext { const context = new UserContext(browser, id); @@ -84,6 +85,10 @@ export class UserContext extends EventEmitter<{ return; } + if (info.userContext !== this.#id) { + return; + } + const browsingContext = BrowsingContext.from( this, undefined, @@ -143,6 +148,7 @@ export class UserContext extends EventEmitter<{ type, ...options, referenceContext: options.referenceContext?.id, + userContext: this.#id, }); const browsingContext = this.#browsingContexts.get(contextId); @@ -161,12 +167,71 @@ export class UserContext extends EventEmitter<{ }) async remove(): Promise<void> { try { - // TODO: Call `removeUserContext` once available. + await this.#session.send('browser.removeUserContext', { + userContext: this.#id, + }); } finally { this.dispose('User context already closed.'); } } + @throwIfDisposed<UserContext>(context => { + // SAFETY: Disposal implies this exists. + return context.#reason!; + }) + async getCookies( + options: GetCookiesOptions = {}, + sourceOrigin: string | undefined = undefined + ): Promise<Bidi.Network.Cookie[]> { + const { + result: {cookies}, + } = await this.#session.send('storage.getCookies', { + ...options, + partition: { + type: 'storageKey', + userContext: this.#id, + sourceOrigin, + }, + }); + return cookies; + } + + @throwIfDisposed<UserContext>(context => { + // SAFETY: Disposal implies this exists. + return context.#reason!; + }) + async setCookie( + cookie: Bidi.Storage.PartialCookie, + sourceOrigin?: string + ): Promise<void> { + await this.#session.send('storage.setCookie', { + cookie, + partition: { + type: 'storageKey', + sourceOrigin, + userContext: this.id, + }, + }); + } + + @throwIfDisposed<UserContext>(context => { + // SAFETY: Disposal implies this exists. + return context.#reason!; + }) + async setPermissions( + origin: string, + descriptor: Bidi.Permissions.PermissionDescriptor, + state: Bidi.Permissions.PermissionState + ): Promise<void> { + await this.#session.send('permissions.setPermission', { + origin, + descriptor, + state, + // @ts-expect-error not standard implementation. + 'goog:userContext': this.#id, + }); + } + [disposeSymbol](): void { this.#reason ??= 'User context already closed, probably because the browser disconnected/closed.'; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/lifecycle.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/lifecycle.ts deleted file mode 100644 index 73b86cba9c..0000000000 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/lifecycle.ts +++ /dev/null @@ -1,119 +0,0 @@ -/** - * @license - * Copyright 2023 Google Inc. - * SPDX-License-Identifier: Apache-2.0 - */ -import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; - -import type { - ObservableInput, - ObservedValueOf, - OperatorFunction, -} from '../../third_party/rxjs/rxjs.js'; -import {catchError} from '../../third_party/rxjs/rxjs.js'; -import type {PuppeteerLifeCycleEvent} from '../cdp/LifecycleWatcher.js'; -import {ProtocolError, TimeoutError} from '../common/Errors.js'; - -/** - * @internal - */ -export type BiDiNetworkIdle = Extract< - PuppeteerLifeCycleEvent, - 'networkidle0' | 'networkidle2' -> | null; - -/** - * @internal - */ -export function getBiDiLifeCycles( - event: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[] -): [ - Extract<PuppeteerLifeCycleEvent, 'load' | 'domcontentloaded'>, - BiDiNetworkIdle, -] { - if (Array.isArray(event)) { - const pageLifeCycle = event.some(lifeCycle => { - return lifeCycle !== 'domcontentloaded'; - }) - ? 'load' - : 'domcontentloaded'; - - const networkLifeCycle = event.reduce((acc, lifeCycle) => { - if (lifeCycle === 'networkidle0') { - return lifeCycle; - } else if (acc !== 'networkidle0' && lifeCycle === 'networkidle2') { - return lifeCycle; - } - return acc; - }, null as BiDiNetworkIdle); - - return [pageLifeCycle, networkLifeCycle]; - } - - if (event === 'networkidle0' || event === 'networkidle2') { - return ['load', event]; - } - - return [event, null]; -} - -/** - * @internal - */ -export const lifeCycleToReadinessState = new Map< - PuppeteerLifeCycleEvent, - Bidi.BrowsingContext.ReadinessState ->([ - ['load', Bidi.BrowsingContext.ReadinessState.Complete], - ['domcontentloaded', Bidi.BrowsingContext.ReadinessState.Interactive], -]); - -export function getBiDiReadinessState( - event: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[] -): [Bidi.BrowsingContext.ReadinessState, BiDiNetworkIdle] { - const lifeCycles = getBiDiLifeCycles(event); - const readiness = lifeCycleToReadinessState.get(lifeCycles[0])!; - return [readiness, lifeCycles[1]]; -} - -/** - * @internal - */ -export const lifeCycleToSubscribedEvent = new Map< - PuppeteerLifeCycleEvent, - 'browsingContext.load' | 'browsingContext.domContentLoaded' ->([ - ['load', 'browsingContext.load'], - ['domcontentloaded', 'browsingContext.domContentLoaded'], -]); - -/** - * @internal - */ -export function getBiDiLifecycleEvent( - event: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[] -): [ - 'browsingContext.load' | 'browsingContext.domContentLoaded', - BiDiNetworkIdle, -] { - const lifeCycles = getBiDiLifeCycles(event); - const bidiEvent = lifeCycleToSubscribedEvent.get(lifeCycles[0])!; - return [bidiEvent, lifeCycles[1]]; -} - -/** - * @internal - */ -export function rewriteNavigationError<T, R extends ObservableInput<T>>( - message: string, - ms: number -): OperatorFunction<T, T | ObservedValueOf<R>> { - return catchError<T, R>(error => { - if (error instanceof ProtocolError) { - error.message += ` at ${message}`; - } else if (error instanceof TimeoutError) { - error.message = `Navigation timeout of ${ms} ms exceeded`; - } - throw error; - }); -} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/util.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/util.ts index 41e88e26c2..e1d64c2f4c 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/util.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/util.ts @@ -6,32 +6,10 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; -import {PuppeteerURL, debugError} from '../common/util.js'; +import {ProtocolError, TimeoutError} from '../common/Errors.js'; +import {PuppeteerURL} from '../common/util.js'; import {BidiDeserializer} from './Deserializer.js'; -import type {BidiRealm} from './Realm.js'; - -/** - * @internal - */ -export async function releaseReference( - client: BidiRealm, - remoteReference: Bidi.Script.RemoteReference -): Promise<void> { - if (!remoteReference.handle) { - return; - } - await client.connection - .send('script.disown', { - target: client.target, - handles: [remoteReference.handle], - }) - .catch(error => { - // Exceptions might happen in case of a page been navigated or closed. - // Swallow these since they are harmless and we don't leak anything in this case. - debugError(error); - }); -} /** * @internal @@ -79,3 +57,20 @@ export function createEvaluationError( error.stack = [details.text, ...stackLines].join('\n'); return error; } + +/** + * @internal + */ +export function rewriteNavigationError( + message: string, + ms: number +): (error: unknown) => never { + return error => { + if (error instanceof ProtocolError) { + error.message += ` at ${message}`; + } else if (error instanceof TimeoutError) { + error.message = `Navigation timeout of ${ms} ms exceeded`; + } + throw error; + }; +} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Binding.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Binding.ts index 7a6a6f8582..7fe372788f 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Binding.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Binding.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {JSHandle} from '../api/JSHandle.js'; import {debugError} from '../common/util.js'; import {DisposableStack} from '../util/disposable.js'; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Browser.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Browser.ts index 7698acd164..5c8a4c24da 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Browser.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Browser.ts @@ -18,7 +18,6 @@ import { type IsPageTargetCallback, type Permission, type TargetFilterCallback, - type WaitForTargetOptions, } from '../api/Browser.js'; import {BrowserContext, BrowserContextEvent} from '../api/BrowserContext.js'; import {CDPSessionEvent, type CDPSession} from '../api/CDPSession.js'; @@ -201,7 +200,7 @@ export class CdpBrowser extends BrowserBase { return this.#isPageTargetCallback; } - override async createIncognitoBrowserContext( + override async createBrowserContext( options: BrowserContextOptions = {} ): Promise<CdpBrowserContext> { const {proxyServer, proxyBypassList} = options; @@ -451,15 +450,6 @@ export class CdpBrowserContext extends BrowserContext { }); } - override waitForTarget( - predicate: (x: Target) => boolean | Promise<boolean>, - options: WaitForTargetOptions = {} - ): Promise<Target> { - return this.#browser.waitForTarget(target => { - return target.browserContext() === this && predicate(target); - }, options); - } - override async pages(): Promise<Page[]> { const pages = await Promise.all( this.targets() diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/EmulationManager.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/EmulationManager.ts index 8598967fe7..823b3b462e 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/EmulationManager.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/EmulationManager.ts @@ -267,13 +267,23 @@ export class EmulationManager { const hasTouch = viewport.hasTouch || false; await Promise.all([ - client.send('Emulation.setDeviceMetricsOverride', { - mobile, - width, - height, - deviceScaleFactor, - screenOrientation, - }), + client + .send('Emulation.setDeviceMetricsOverride', { + mobile, + width, + height, + deviceScaleFactor, + screenOrientation, + }) + .catch(err => { + if ( + err.message.includes('Target does not support metrics override') + ) { + debugError(err); + return; + } + throw err; + }), client.send('Emulation.setTouchEmulationEnabled', { enabled: hasTouch, }), diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Frame.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Frame.ts index 844120d7ff..edc7009b11 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Frame.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Frame.ts @@ -20,6 +20,7 @@ import type { DeviceRequestPromptManager, } from './DeviceRequestPrompt.js'; import type {FrameManager} from './FrameManager.js'; +import type {IsolatedWorldChart} from './IsolatedWorld.js'; import {IsolatedWorld} from './IsolatedWorld.js'; import {MAIN_WORLD, PUPPETEER_WORLD} from './IsolatedWorlds.js'; import { @@ -35,6 +36,7 @@ export class CdpFrame extends Frame { #url = ''; #detached = false; #client!: CDPSession; + worlds!: IsolatedWorldChart; _frameManager: FrameManager; override _id: string; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPRequest.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPRequest.ts index 029e77470b..1331513e19 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPRequest.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPRequest.ts @@ -28,6 +28,7 @@ import type {CdpHTTPResponse} from './HTTPResponse.js'; * @internal */ export class CdpHTTPRequest extends HTTPRequest { + override id: string; declare _redirectChain: CdpHTTPRequest[]; declare _response: CdpHTTPResponse | null; @@ -91,7 +92,7 @@ export class CdpHTTPRequest extends HTTPRequest { ) { super(); this.#client = client; - this._requestId = data.requestId; + this.id = data.requestId; this.#isNavigationRequest = data.requestId === data.loaderId && data.type === 'Document'; this._interceptionId = interceptionId; @@ -188,7 +189,7 @@ export class CdpHTTPRequest extends HTTPRequest { override async fetchPostData(): Promise<string | undefined> { try { const result = await this.#client.send('Network.getRequestPostData', { - requestId: this._requestId, + requestId: this.id, }); return result.postData; } catch (err) { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPResponse.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPResponse.ts index 2b2264ffd4..eb92ab07e3 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPResponse.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPResponse.ts @@ -130,7 +130,7 @@ export class CdpHTTPResponse extends HTTPResponse { const response = await this.#client.send( 'Network.getResponseBody', { - requestId: this.#request._requestId, + requestId: this.#request.id, } ); return Buffer.from( diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Input.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Input.ts index 9bfafddcf3..0674ef4634 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Input.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Input.ts @@ -10,16 +10,16 @@ import type {CDPSession} from '../api/CDPSession.js'; import type {Point} from '../api/ElementHandle.js'; import { Keyboard, - type KeyDownOptions, - type KeyPressOptions, Mouse, MouseButton, + Touchscreen, + type KeyDownOptions, + type KeyPressOptions, + type KeyboardTypeOptions, type MouseClickOptions, type MouseMoveOptions, type MouseOptions, type MouseWheelOptions, - Touchscreen, - type KeyboardTypeOptions, } from '../api/Input.js'; import { _keyDefinitions, @@ -573,6 +573,7 @@ export class CdpTouchscreen extends Touchscreen { y: Math.round(y), radiusX: 0.5, radiusY: 0.5, + force: 0.5, }, ], modifiers: this.#keyboard._modifiers, @@ -588,6 +589,7 @@ export class CdpTouchscreen extends Touchscreen { y: Math.round(y), radiusX: 0.5, radiusY: 0.5, + force: 0.5, }, ], modifiers: this.#keyboard._modifiers, diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/LifecycleWatcher.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/LifecycleWatcher.ts index a4f5aaa468..fe71ca52fc 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/LifecycleWatcher.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/LifecycleWatcher.ts @@ -191,14 +191,14 @@ export class LifecycleWatcher { } #onRequestFailed(request: HTTPRequest): void { - if (this.#navigationRequest?._requestId !== request._requestId) { + if (this.#navigationRequest?.id !== request.id) { return; } this.#navigationResponseReceived?.resolve(); } #onResponse(response: HTTPResponse): void { - if (this.#navigationRequest?._requestId !== response.request()._requestId) { + if (this.#navigationRequest?.id !== response.request().id) { return; } this.#navigationResponseReceived?.resolve(); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.test.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.test.ts index c3e9a8f609..96f0d20963 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.test.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.test.ts @@ -128,6 +128,7 @@ describe('NetworkManager', () => { url: 'http://localhost:8907/redirect/1.html', status: 302, statusText: 'Found', + charset: 'utf-8', headers: { location: '/redirect/2.html', Date: 'Fri, 19 Nov 2021 09:53:58 GMT', @@ -217,6 +218,7 @@ describe('NetworkManager', () => { url: 'http://localhost:8907/redirect/2.html', status: 302, statusText: 'Found', + charset: 'utf-8', headers: { location: '/redirect/3.html', Date: 'Fri, 19 Nov 2021 09:53:58 GMT', @@ -321,6 +323,7 @@ describe('NetworkManager', () => { url: 'http://localhost:8907/redirect/3.html', status: 302, statusText: 'Found', + charset: 'utf-8', headers: { location: 'http://localhost:8907/empty.html', Date: 'Fri, 19 Nov 2021 09:53:58 GMT', @@ -433,6 +436,7 @@ describe('NetworkManager', () => { 'Keep-Alive': 'timeout=5', 'Content-Length': '0', }, + charset: 'utf-8', mimeType: 'text/html', connectionReused: true, connectionId: 322, @@ -613,6 +617,7 @@ describe('NetworkManager', () => { connection: 'keep-alive', 'content-length': '85862', }, + charset: 'utf-8', mimeType: 'text/plain', connectionReused: false, connectionId: 119, @@ -725,6 +730,7 @@ describe('NetworkManager', () => { url: 'http://10.1.0.39:42915/empty.html', status: 200, statusText: 'OK', + charset: 'utf-8', headers: { 'Cache-Control': 'no-cache, no-store', Connection: 'keep-alive', @@ -932,6 +938,7 @@ describe('NetworkManager', () => { url: 'http://127.0.0.1:54590/empty.html', status: 200, statusText: 'OK', + charset: 'utf-8', headers: { 'Cache-Control': 'no-cache, no-store', Connection: 'keep-alive', @@ -1036,6 +1043,7 @@ describe('NetworkManager', () => { url: 'http://localhost:56295/empty.html', status: 200, statusText: 'OK', + charset: 'utf-8', headers: { 'Cache-Control': 'no-cache, no-store', Connection: 'keep-alive', @@ -1221,6 +1229,7 @@ describe('NetworkManager', () => { url: 'http://localhost:3000/', status: 200, statusText: 'OK', + charset: 'utf-8', headers: { 'Cache-Control': 'max-age=5', Connection: 'keep-alive', @@ -1394,6 +1403,7 @@ describe('NetworkManager', () => { url: 'http://localhost:3000/redirect', status: 302, statusText: 'Found', + charset: 'utf-8', headers: { Connection: 'keep-alive', Date: 'Wed, 05 Apr 2023 12:39:13 GMT', @@ -1457,6 +1467,7 @@ describe('NetworkManager', () => { url: 'http://localhost:3000/', status: 200, statusText: 'OK', + charset: 'utf-8', headers: { 'Cache-Control': 'max-age=5', 'Content-Type': 'text/html; charset=utf-8', diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.ts index 8b24b9a748..4fd61116d2 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.ts @@ -36,11 +36,17 @@ export interface Credentials { * @public */ export interface NetworkConditions { - // Download speed (bytes/s) + /** + * Download speed (bytes/s) + */ download: number; - // Upload speed (bytes/s) + /** + * Upload speed (bytes/s) + */ upload: number; - // Latency (ms) + /** + * Latency (ms) + */ latency: number; } @@ -631,7 +637,7 @@ export class NetworkManager extends EventEmitter<NetworkManagerEvents> { } #forgetRequest(request: CdpHTTPRequest, events: boolean): void { - const requestId = request._requestId; + const requestId = request.id; const interceptionId = request._interceptionId; this.#networkEventManager.forgetRequest(requestId); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Page.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Page.ts index 491637f0ea..d5341cf3bb 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Page.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Page.ts @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {Readable} from 'stream'; - import type {Protocol} from 'devtools-protocol'; import {firstValueFrom, from, raceWith} from '../../third_party/rxjs/rxjs.js'; @@ -32,6 +30,11 @@ import { ConsoleMessage, type ConsoleMessageType, } from '../common/ConsoleMessage.js'; +import type { + Cookie, + DeleteCookiesRequest, + CookieParam, +} from '../common/Cookie.js'; import {TargetCloseError} from '../common/Errors.js'; import {FileChooser} from '../common/FileChooser.js'; import {NetworkManagerEvent} from '../common/NetworkManagerEvents.js'; @@ -80,6 +83,15 @@ import { } from './utils.js'; import {CdpWebWorker} from './WebWorker.js'; +function convertConsoleMessageLevel(method: string): ConsoleMessageType { + switch (method) { + case 'warning': + return 'warn'; + default: + return method as ConsoleMessageType; + } +} + /** * @internal */ @@ -346,6 +358,8 @@ export class CdpPage extends Page { const worker = new CdpWebWorker( session, session._target().url(), + session._target()._targetId, + session._target().type(), this.#addConsoleMessage.bind(this), this.#handleException.bind(this) ); @@ -470,7 +484,12 @@ export class CdpPage extends Page { if (source !== 'worker') { this.emit( PageEvent.Console, - new ConsoleMessage(level, text, [], [{url, lineNumber}]) + new ConsoleMessage( + convertConsoleMessageLevel(level), + text, + [], + [{url, lineNumber}] + ) ); } } @@ -572,16 +591,14 @@ export class CdpPage extends Page { ) as HandleFor<Prototype[]>; } - override async cookies( - ...urls: string[] - ): Promise<Protocol.Network.Cookie[]> { + override async cookies(...urls: string[]): Promise<Cookie[]> { const originalCookies = ( await this.#primaryTargetClient.send('Network.getCookies', { urls: urls.length ? urls : [this.url()], }) ).cookies; - const unsupportedCookieAttributes = ['priority']; + const unsupportedCookieAttributes = ['sourcePort']; const filterUnsupportedAttributes = ( cookie: Protocol.Network.Cookie ): Protocol.Network.Cookie => { @@ -594,7 +611,7 @@ export class CdpPage extends Page { } override async deleteCookie( - ...cookies: Protocol.Network.DeleteCookiesRequest[] + ...cookies: DeleteCookiesRequest[] ): Promise<void> { const pageURL = this.url(); for (const cookie of cookies) { @@ -606,9 +623,7 @@ export class CdpPage extends Page { } } - override async setCookie( - ...cookies: Protocol.Network.CookieParam[] - ): Promise<void> { + override async setCookie(...cookies: CookieParam[]): Promise<void> { const pageURL = this.url(); const startsWithHTTP = pageURL.startsWith('http'); const items = cookies.map(cookie => { @@ -810,7 +825,11 @@ export class CdpPage extends Page { const values = event.args.map(arg => { return createCdpHandle(context._world, arg); }); - this.#addConsoleMessage(event.type, values, event.stackTrace); + this.#addConsoleMessage( + convertConsoleMessageLevel(event.type), + values, + event.stackTrace + ); } async #onBindingCalled( @@ -842,7 +861,7 @@ export class CdpPage extends Page { } #addConsoleMessage( - eventType: ConsoleMessageType, + eventType: string, args: JSHandle[], stackTrace?: Protocol.Runtime.StackTrace ): void { @@ -874,7 +893,7 @@ export class CdpPage extends Page { } } const message = new ConsoleMessage( - eventType, + convertConsoleMessageLevel(eventType), textTokens.join(' '), args, stackTraceLocations @@ -1086,7 +1105,9 @@ export class CdpPage extends Page { return data; } - override async createPDFStream(options: PDFOptions = {}): Promise<Readable> { + override async createPDFStream( + options: PDFOptions = {} + ): Promise<ReadableStream<Uint8Array>> { const {timeout: ms = this._timeoutSettings.timeout()} = options; const { landscape, @@ -1102,6 +1123,7 @@ export class CdpPage extends Page { preferCSSPageSize, omitBackground, tagged: generateTaggedPDF, + outline: generateDocumentOutline, } = parsePDFOptions(options); if (omitBackground) { @@ -1127,6 +1149,7 @@ export class CdpPage extends Page { pageRanges, preferCSSPageSize, generateTaggedPDF, + generateDocumentOutline, } ); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/PredefinedNetworkConditions.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/PredefinedNetworkConditions.ts index df035ae52b..2e30f900c3 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/PredefinedNetworkConditions.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/PredefinedNetworkConditions.ts @@ -40,10 +40,3 @@ export const PredefinedNetworkConditions = Object.freeze({ latency: 150 * 3.75, } as NetworkConditions, }); - -/** - * @deprecated Import {@link PredefinedNetworkConditions}. - * - * @public - */ -export const networkConditions = PredefinedNetworkConditions; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Target.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Target.ts index b3e9ea83ec..ab8b00475b 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Target.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Target.ts @@ -290,6 +290,8 @@ export class WorkerTarget extends CdpTarget { return new CdpWebWorker( client, this._getTargetInfo().url, + this._targetId, + this.type(), () => {} /* consoleAPICalled */, () => {} /* exceptionThrown */ ); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/WebWorker.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/WebWorker.ts index 552e8a6cf5..ed2407ba66 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/WebWorker.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/WebWorker.ts @@ -7,8 +7,8 @@ import type {Protocol} from 'devtools-protocol'; import type {CDPSession} from '../api/CDPSession.js'; import type {Realm} from '../api/Realm.js'; +import {TargetType} from '../api/Target.js'; import {WebWorker} from '../api/WebWorker.js'; -import type {ConsoleMessageType} from '../common/ConsoleMessage.js'; import {TimeoutSettings} from '../common/TimeoutSettings.js'; import {debugError} from '../common/util.js'; @@ -20,7 +20,7 @@ import {CdpJSHandle} from './JSHandle.js'; * @internal */ export type ConsoleAPICalledCallback = ( - eventType: ConsoleMessageType, + eventType: string, handles: CdpJSHandle[], trace?: Protocol.Runtime.StackTrace ) => void; @@ -38,15 +38,21 @@ export type ExceptionThrownCallback = ( export class CdpWebWorker extends WebWorker { #world: IsolatedWorld; #client: CDPSession; + readonly #id: string; + readonly #targetType: TargetType; constructor( client: CDPSession, url: string, + targetId: string, + targetType: TargetType, consoleAPICalled: ConsoleAPICalledCallback, exceptionThrown: ExceptionThrownCallback ) { super(url); + this.#id = targetId; this.#client = client; + this.#targetType = targetType; this.#world = new IsolatedWorld(this, new TimeoutSettings()); this.#client.once('Runtime.executionContextCreated', async event => { @@ -80,4 +86,25 @@ export class CdpWebWorker extends WebWorker { get client(): CDPSession { return this.#client; } + + override async close(): Promise<void> { + switch (this.#targetType) { + case TargetType.SERVICE_WORKER: + case TargetType.SHARED_WORKER: { + // For service and shared workers we need to close the target and detach to allow + // the worker to stop. + await this.client.connection()?.send('Target.closeTarget', { + targetId: this.#id, + }); + await this.client.connection()?.send('Target.detachFromTarget', { + sessionId: this.client.id(), + }); + break; + } + default: + await this.evaluate(() => { + self.close(); + }); + } + } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/BrowserConnector.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/BrowserConnector.ts index 217e53bedd..4c8308da6e 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/BrowserConnector.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/BrowserConnector.ts @@ -14,7 +14,6 @@ import {isErrorLike} from '../util/ErrorLike.js'; import type {ConnectionTransport} from './ConnectionTransport.js'; import type {ConnectOptions} from './ConnectOptions.js'; import type {BrowserConnectOptions} from './ConnectOptions.js'; -import {getFetch} from './fetch.js'; const getWebSocketTransportClass = async () => { return isNode @@ -93,9 +92,8 @@ async function getConnectionTransport( async function getWSEndpoint(browserURL: string): Promise<string> { const endpointURL = new URL('/json/version', browserURL); - const fetch = await getFetch(); try { - const result = await fetch(endpointURL.toString(), { + const result = await globalThis.fetch(endpointURL.toString(), { method: 'GET', }); if (!result.ok) { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/Configuration.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/Configuration.ts index c64d109a7c..fe71e57587 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/Configuration.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/Configuration.ts @@ -32,7 +32,13 @@ export interface Configuration { * See {@link PuppeteerNode.launch | puppeteer.launch} on how executable path * is inferred. * - * @defaultValue A compatible-revision of the browser. + * Use a specific browser version (e.g., 119.0.6045.105). If you use an alias + * such `stable` or `canary` it will only work during the installation of + * Puppeteer and it will fail when launching the browser. + * + * @example 119.0.6045.105 + * @defaultValue The pinned browser version supported by the current Puppeteer + * version. */ browserRevision?: string; /** @@ -51,20 +57,12 @@ export interface Configuration { * @remarks * This must include the protocol and may even need a path prefix. * - * @defaultValue Either https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing or + * @defaultValue Either https://storage.googleapis.com/chrome-for-testing-public or * https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central, * depending on the product. */ downloadBaseUrl?: string; /** - * Specifies the path for the downloads folder. - * - * Can be overridden by `PUPPETEER_DOWNLOAD_PATH`. - * - * @defaultValue `<cacheDirectory>` - */ - downloadPath?: string; - /** * Specifies an executable path to be used in * {@link PuppeteerNode.launch | puppeteer.launch}. * diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/ConsoleMessage.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/ConsoleMessage.ts index 85d2db9f75..c2aad7679d 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/ConsoleMessage.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/ConsoleMessage.ts @@ -35,7 +35,7 @@ export type ConsoleMessageType = | 'debug' | 'info' | 'error' - | 'warning' + | 'warn' | 'dir' | 'dirxml' | 'table' diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/Cookie.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/Cookie.ts new file mode 100644 index 0000000000..c9f7283075 --- /dev/null +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/Cookie.ts @@ -0,0 +1,186 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Represents the cookie's 'SameSite' status: + * https://tools.ietf.org/html/draft-west-first-party-cookies + * + * @public + */ +export type CookieSameSite = 'Strict' | 'Lax' | 'None'; + +/** + * Represents the cookie's 'Priority' status: + * https://tools.ietf.org/html/draft-west-cookie-priority-00 + * + * @public + */ +export type CookiePriority = 'Low' | 'Medium' | 'High'; + +/** + * Represents the source scheme of the origin that originally set the cookie. A value of + * "Unset" allows protocol clients to emulate legacy cookie scope for the scheme. + * This is a temporary ability and it will be removed in the future. + * + * @public + */ +export type CookieSourceScheme = 'Unset' | 'NonSecure' | 'Secure'; + +/** + * Represents a cookie object. + * + * @public + */ +export interface Cookie { + /** + * Cookie name. + */ + name: string; + /** + * Cookie value. + */ + value: string; + /** + * Cookie domain. + */ + domain: string; + /** + * Cookie path. + */ + path: string; + /** + * Cookie expiration date as the number of seconds since the UNIX epoch. Set to `-1` for + * session cookies + */ + expires: number; + /** + * Cookie size. + */ + size: number; + /** + * True if cookie is http-only. + */ + httpOnly: boolean; + /** + * True if cookie is secure. + */ + secure: boolean; + /** + * True in case of session cookie. + */ + session: boolean; + /** + * Cookie SameSite type. + */ + sameSite?: CookieSameSite; + /** + * Cookie Priority. Supported only in Chrome. + */ + priority?: CookiePriority; + /** + * True if cookie is SameParty. Supported only in Chrome. + */ + sameParty?: boolean; + /** + * Cookie source scheme type. Supported only in Chrome. + */ + sourceScheme?: CookieSourceScheme; + /** + * Cookie partition key. The site of the top-level URL the browser was visiting at the + * start of the request to the endpoint that set the cookie. Supported only in Chrome. + */ + partitionKey?: string; + /** + * True if cookie partition key is opaque. Supported only in Chrome. + */ + partitionKeyOpaque?: boolean; +} + +/** + * Cookie parameter object + * + * @public + */ +export interface CookieParam { + /** + * Cookie name. + */ + name: string; + /** + * Cookie value. + */ + value: string; + /** + * The request-URI to associate with the setting of the cookie. This value can affect + * the default domain, path, and source scheme values of the created cookie. + */ + url?: string; + /** + * Cookie domain. + */ + domain?: string; + /** + * Cookie path. + */ + path?: string; + /** + * True if cookie is secure. + */ + secure?: boolean; + /** + * True if cookie is http-only. + */ + httpOnly?: boolean; + /** + * Cookie SameSite type. + */ + sameSite?: CookieSameSite; + /** + * Cookie expiration date, session cookie if not set + */ + expires?: number; + /** + * Cookie Priority. Supported only in Chrome. + */ + priority?: CookiePriority; + /** + * True if cookie is SameParty. Supported only in Chrome. + */ + sameParty?: boolean; + /** + * Cookie source scheme type. Supported only in Chrome. + */ + sourceScheme?: CookieSourceScheme; + /** + * Cookie partition key. The site of the top-level URL the browser was visiting at the + * start of the request to the endpoint that set the cookie. If not set, the cookie will + * be set as not partitioned. + */ + partitionKey?: string; +} + +/** + * @public + */ +export interface DeleteCookiesRequest { + /** + * Name of the cookies to remove. + */ + name: string; + /** + * If specified, deletes all the cookies with the given name where domain and path match + * provided URL. Otherwise, deletes only cookies related to the current page's domain. + */ + url?: string; + /** + * If specified, deletes only cookies with the exact domain. + */ + domain?: string; + /** + * If specified, deletes only cookies with the exact path. + */ + path?: string; +} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/Device.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/Device.ts index dbf5c13c95..1f1a35dd0b 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/Device.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/Device.ts @@ -1543,10 +1543,3 @@ for (const device of knownDevices) { * @public */ export const KnownDevices = Object.freeze(knownDevicesByName); - -/** - * @deprecated Import {@link KnownDevices} - * - * @public - */ -export const devices = KnownDevices; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/Errors.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/Errors.ts index 8225d64f07..4d0a43ea33 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/Errors.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/Errors.ts @@ -5,11 +5,11 @@ */ /** - * @deprecated Do not use. + * The base class for all Puppeteer-specific errors * * @public */ -export class CustomError extends Error { +export class PuppeteerError extends Error { /** * @internal */ @@ -36,14 +36,14 @@ export class CustomError extends Error { * * @public */ -export class TimeoutError extends CustomError {} +export class TimeoutError extends PuppeteerError {} /** * ProtocolError is emitted whenever there is an error from the protocol. * * @public */ -export class ProtocolError extends CustomError { +export class ProtocolError extends PuppeteerError { #code?: number; #originalMessage = ''; @@ -76,49 +76,9 @@ export class ProtocolError extends CustomError { * * @public */ -export class UnsupportedOperation extends CustomError {} +export class UnsupportedOperation extends PuppeteerError {} /** * @internal */ export class TargetCloseError extends ProtocolError {} - -/** - * @deprecated Do not use. - * - * @public - */ -export interface PuppeteerErrors { - TimeoutError: typeof TimeoutError; - ProtocolError: typeof ProtocolError; -} - -/** - * @deprecated Import error classes directly. - * - * Puppeteer methods might throw errors if they are unable to fulfill a request. - * For example, `page.waitForSelector(selector[, options])` might fail if the - * selector doesn't match any nodes during the given timeframe. - * - * For certain types of errors Puppeteer uses specific error classes. These - * classes are available via `puppeteer.errors`. - * - * @example - * An example of handling a timeout error: - * - * ```ts - * try { - * await page.waitForSelector('.foo'); - * } catch (e) { - * if (e instanceof TimeoutError) { - * // Do something if this is a timeout. - * } - * } - * ``` - * - * @public - */ -export const errors: PuppeteerErrors = Object.freeze({ - TimeoutError, - ProtocolError, -}); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.test.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.test.ts index cf05ef6700..f3875e99e8 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.test.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.test.ts @@ -19,7 +19,7 @@ describe('EventEmitter', () => { }); describe('on', () => { - const onTests = (methodName: 'on' | 'addListener'): void => { + const onTests = (methodName: 'on'): void => { it(`${methodName}: adds an event listener that is fired when the event is emitted`, () => { const listener = sinon.spy(); emitter[methodName]('foo', listener); @@ -43,12 +43,10 @@ describe('EventEmitter', () => { }); }; onTests('on'); - // we support addListener for legacy reasons - onTests('addListener'); }); describe('off', () => { - const offTests = (methodName: 'off' | 'removeListener'): void => { + const offTests = (methodName: 'off'): void => { it(`${methodName}: removes the listener so it is no longer called`, () => { const listener = sinon.spy(); emitter.on('foo', listener); @@ -67,8 +65,6 @@ describe('EventEmitter', () => { }); }; offTests('off'); - // we support removeListener for legacy reasons - offTests('removeListener'); }); describe('once', () => { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.ts index 4a8bcb801f..0aace8b2eb 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.ts @@ -27,18 +27,6 @@ export interface CommonEventEmitter<Events extends Record<EventType, unknown>> { handler?: Handler<Events[Key]> ): this; emit<Key extends keyof Events>(type: Key, event: Events[Key]): boolean; - /* To maintain parity with the built in NodeJS event emitter which uses removeListener - * rather than `off`. - * If you're implementing new code you should use `off`. - */ - addListener<Key extends keyof Events>( - type: Key, - handler: Handler<Events[Key]> - ): this; - removeListener<Key extends keyof Events>( - type: Key, - handler: Handler<Events[Key]> - ): this; once<Key extends keyof Events>( type: Key, handler: Handler<Events[Key]> @@ -149,30 +137,6 @@ export class EventEmitter<Events extends Record<EventType, unknown>> } /** - * Remove an event listener. - * - * @deprecated please use {@link EventEmitter.off} instead. - */ - removeListener<Key extends keyof EventsWithWildcard<Events>>( - type: Key, - handler: Handler<EventsWithWildcard<Events>[Key]> - ): this { - return this.off(type, handler); - } - - /** - * Add an event listener. - * - * @deprecated please use {@link EventEmitter.on} instead. - */ - addListener<Key extends keyof EventsWithWildcard<Events>>( - type: Key, - handler: Handler<EventsWithWildcard<Events>[Key]> - ): this { - return this.on(type, handler); - } - - /** * Like `on` but the listener will only be fired once and then it will be removed. * @param type - the event you'd like to listen to * @param handler - the handler function to run when the event occurs diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/PDFOptions.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/PDFOptions.ts index 7cae9191a9..f87ec6817b 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/PDFOptions.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/PDFOptions.ts @@ -158,11 +158,23 @@ export interface PDFOptions { omitBackground?: boolean; /** * Generate tagged (accessible) PDF. - * @defaultValue `false` + * @defaultValue `true` * @experimental */ tagged?: boolean; /** + * Generate document outline. + * + * @remarks + * If this is enabled the PDF will also be tagged (accessible) + * Currently only works in old Headless (headless = 'shell') + * crbug/840455#c47 + * + * @defaultValue `false` + * @experimental + */ + outline?: boolean; + /** * Timeout in milliseconds. Pass `0` to disable timeout. * @defaultValue `30_000` */ diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/ScriptInjector.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/ScriptInjector.ts index 0264c9175f..d505d6c5ff 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/ScriptInjector.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/ScriptInjector.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {source as injectedSource} from '../generated/injected.js'; /** diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/common.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/common.ts index 6ef8925605..bf4274fcf1 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/common.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/common.ts @@ -10,12 +10,12 @@ export * from './Configuration.js'; export * from './ConnectionTransport.js'; export * from './ConnectOptions.js'; export * from './ConsoleMessage.js'; +export * from './Cookie.js'; export * from './CustomQueryHandler.js'; export * from './Debug.js'; export * from './Device.js'; export * from './Errors.js'; export * from './EventEmitter.js'; -export * from './fetch.js'; export * from './FileChooser.js'; export * from './GetQueryHandler.js'; export * from './HandleIterator.js'; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/fetch.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/fetch.ts deleted file mode 100644 index 6c7a2b451c..0000000000 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/fetch.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @license - * Copyright 2020 Google Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * Gets the global version if we're in the browser, else loads the node-fetch module. - * - * @internal - */ -export const getFetch = async (): Promise<typeof fetch> => { - return (globalThis as any).fetch || (await import('cross-fetch')).fetch; -}; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/util.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/util.ts index 2c8f76f664..f84453c612 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/util.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/util.ts @@ -5,13 +5,19 @@ */ import type FS from 'fs/promises'; -import type {Readable} from 'stream'; -import {map, NEVER, Observable, timer} from '../../third_party/rxjs/rxjs.js'; +import type {OperatorFunction} from '../../third_party/rxjs/rxjs.js'; +import { + filter, + from, + map, + mergeMap, + NEVER, + Observable, + timer, +} from '../../third_party/rxjs/rxjs.js'; import type {CDPSession} from '../api/CDPSession.js'; -import {isNode} from '../environment.js'; import {assert} from '../util/assert.js'; -import {isErrorLike} from '../util/ErrorLike.js'; import {debug} from './Debug.js'; import {TimeoutError} from './Errors.js'; @@ -209,29 +215,39 @@ export async function importFSPromises(): Promise<typeof FS> { * @internal */ export async function getReadableAsBuffer( - readable: Readable, + readable: ReadableStream<Uint8Array>, path?: string ): Promise<Buffer | null> { - const buffers = []; + const buffers: Uint8Array[] = []; + const reader = readable.getReader(); if (path) { const fs = await importFSPromises(); const fileHandle = await fs.open(path, 'w+'); try { - for await (const chunk of readable) { - buffers.push(chunk); - await fileHandle.writeFile(chunk); + while (true) { + const {done, value} = await reader.read(); + if (done) { + break; + } + buffers.push(value); + await fileHandle.writeFile(value); } } finally { await fileHandle.close(); } } else { - for await (const chunk of readable) { - buffers.push(chunk); + while (true) { + const {done, value} = await reader.read(); + if (done) { + break; + } + buffers.push(value); } } try { return Buffer.concat(buffers); } catch (error) { + debugError(error); return null; } } @@ -239,39 +255,34 @@ export async function getReadableAsBuffer( /** * @internal */ + +/** + * @internal + */ export async function getReadableFromProtocolStream( client: CDPSession, handle: string -): Promise<Readable> { - // TODO: Once Node 18 becomes the lowest supported version, we can migrate to - // ReadableStream. - if (!isNode) { - throw new Error('Cannot create a stream outside of Node.js environment.'); - } +): Promise<ReadableStream<Uint8Array>> { + return new ReadableStream({ + async pull(controller) { + function getUnit8Array(data: string, isBase64: boolean): Uint8Array { + if (isBase64) { + return Uint8Array.from(atob(data), m => { + return m.codePointAt(0)!; + }); + } + const encoder = new TextEncoder(); + return encoder.encode(data); + } - const {Readable} = await import('stream'); + const {data, base64Encoded, eof} = await client.send('IO.read', { + handle, + }); - let eof = false; - return new Readable({ - async read(size: number) { + controller.enqueue(getUnit8Array(data, base64Encoded ?? false)); if (eof) { - return; - } - - try { - const response = await client.send('IO.read', {handle, size}); - this.push(response.data, response.base64Encoded ? 'base64' : undefined); - if (response.eof) { - eof = true; - await client.send('IO.close', {handle}); - this.push(null); - } - } catch (error) { - if (isErrorLike(error)) { - this.destroy(error); - return; - } - throw error; + await client.send('IO.close', {handle}); + controller.close(); } }, }); @@ -349,7 +360,8 @@ export function parsePDFOptions( pageRanges: '', preferCSSPageSize: false, omitBackground: false, - tagged: false, + outline: false, + tagged: true, }; let width = 8.5; @@ -375,6 +387,11 @@ export function parsePDFOptions( convertPrintParameterToInches(options.margin?.right, lengthUnit) || 0, }; + // Quirk https://bugs.chromium.org/p/chromium/issues/detail?id=840455#c44 + if (options.outline) { + options.tagged = true; + } + return { ...defaults, ...options, @@ -445,3 +462,21 @@ export function fromEmitterEvent< }; }); } + +/** + * @internal + */ +export function filterAsync<T>( + predicate: (value: T) => boolean | PromiseLike<boolean> +): OperatorFunction<T, T> { + return mergeMap<T, Observable<T>>((value): Observable<T> => { + return from(Promise.resolve(predicate(value))).pipe( + filter(isMatch => { + return isMatch; + }), + map(() => { + return value; + }) + ); + }); +} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/injected/util.ts b/remote/test/puppeteer/packages/puppeteer-core/src/injected/util.ts index 34fe8f7748..cfc209ba57 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/injected/util.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/injected/util.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ const HIDDEN_VISIBILITY_VALUES = ['hidden', 'collapse']; /** diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/node/ChromeLauncher.ts b/remote/test/puppeteer/packages/puppeteer-core/src/node/ChromeLauncher.ts index 51d5a19983..0cec3de9ae 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/node/ChromeLauncher.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/node/ChromeLauncher.ts @@ -36,25 +36,6 @@ export class ChromeLauncher extends ProductLauncher { } override launch(options: PuppeteerNodeLaunchOptions = {}): Promise<Browser> { - const headless = options.headless ?? true; - if ( - headless === true && - this.puppeteer.configuration.logLevel === 'warn' && - !Boolean(process.env['PUPPETEER_DISABLE_HEADLESS_WARNING']) - ) { - console.warn( - [ - '\x1B[1m\x1B[43m\x1B[30m', - 'Puppeteer old Headless deprecation warning:\x1B[0m\x1B[33m', - ' In the near future `headless: true` will default to the new Headless mode', - ' for Chrome instead of the old Headless implementation. For more', - ' information, please see https://developer.chrome.com/articles/new-headless/.', - ' Consider opting in early by passing `headless: "new"` to `puppeteer.launch()`', - ' If you encounter any bugs, please report them to https://github.com/puppeteer/puppeteer/issues/new/choose.\x1B[0m\n', - ].join('\n ') - ); - } - if ( this.puppeteer.configuration.logLevel === 'warn' && process.platform === 'darwin' && @@ -231,6 +212,7 @@ export class ChromeLauncher extends ProductLauncher { '--disable-sync', '--enable-automation', '--export-tagged-pdf', + '--generate-pdf-document-outline', '--force-color-profile=srgb', '--metrics-recording-only', '--no-first-run', @@ -253,7 +235,7 @@ export class ChromeLauncher extends ProductLauncher { } if (headless) { chromeArguments.push( - headless === 'new' ? '--headless=new' : '--headless', + headless === 'shell' ? '--headless' : '--headless=new', '--hide-scrollbars', '--mute-audio' ); @@ -271,7 +253,7 @@ export class ChromeLauncher extends ProductLauncher { override executablePath( channel?: ChromeReleaseChannel, - headless?: boolean | 'new' + headless?: boolean | 'shell' ): string { if (channel) { return computeSystemExecutablePath({ diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/node/FirefoxLauncher.ts b/remote/test/puppeteer/packages/puppeteer-core/src/node/FirefoxLauncher.ts index eb4f375fc7..1af09192ec 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/node/FirefoxLauncher.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/node/FirefoxLauncher.ts @@ -43,12 +43,20 @@ export class FirefoxLauncher extends ProductLauncher { return { ...extraPrefsFirefox, ...(protocol === 'webDriverBiDi' - ? {} + ? { + // Only enable the WebDriver BiDi protocol + 'remote.active-protocols': 1, + } : { // Do not close the window when the last tab gets closed 'browser.tabs.closeWindowWithLastTab': false, + // Prevent various error message on the console + // jest-puppeteer asserts that no error message is emitted by the console + 'network.cookie.cookieBehavior': 0, // Temporarily force disable BFCache in parent (https://bit.ly/bug-1732263) 'fission.bfcacheInParent': false, + // Only enable the CDP protocol + 'remote.active-protocols': 2, }), // Force all web content to use a single content process. TODO: remove // this once Firefox supports mouse event dispatch from the main frame diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/node/LaunchOptions.ts b/remote/test/puppeteer/packages/puppeteer-core/src/node/LaunchOptions.ts index 28e0b595df..d7717e45c5 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/node/LaunchOptions.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/node/LaunchOptions.ts @@ -17,13 +17,18 @@ export interface BrowserLaunchArgumentOptions { * Whether to run the browser in headless mode. * * @remarks - * In the future `headless: true` will be equivalent to `headless: 'new'`. - * You can read more about the change {@link https://developer.chrome.com/articles/new-headless/ | here}. - * Consider opting in early by setting the value to `"new"`. + * + * - `true` launches the browser in the + * {@link https://developer.chrome.com/articles/new-headless/ | new headless} + * mode. + * + * - `'shell'` launches + * {@link https://developer.chrome.com/blog/chrome-headless-shell | shell} + * known as the old headless mode. * * @defaultValue `true` */ - headless?: boolean | 'new'; + headless?: boolean | 'shell'; /** * Path to a user data directory. * {@link https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/user_data_dir.md | see the Chromium docs} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/node/ProductLauncher.ts b/remote/test/puppeteer/packages/puppeteer-core/src/node/ProductLauncher.ts index ab3432cd3a..2da07e8f7c 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/node/ProductLauncher.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/node/ProductLauncher.ts @@ -393,7 +393,7 @@ export abstract class ProductLauncher { /** * @internal */ - protected resolveExecutablePath(headless?: boolean | 'new'): string { + protected resolveExecutablePath(headless?: boolean | 'shell'): string { let executablePath = this.puppeteer.configuration.executablePath; if (executablePath) { if (!existsSync(executablePath)) { @@ -404,10 +404,10 @@ export abstract class ProductLauncher { return executablePath; } - function productToBrowser(product?: Product, headless?: boolean | 'new') { + function productToBrowser(product?: Product, headless?: boolean | 'shell') { switch (product) { case 'chrome': - if (headless === true) { + if (headless === 'shell') { return InstalledBrowser.CHROMEHEADLESSSHELL; } return InstalledBrowser.CHROME; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/node/PuppeteerNode.ts b/remote/test/puppeteer/packages/puppeteer-core/src/node/PuppeteerNode.ts index e50e09acdb..726ee24cbb 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/node/PuppeteerNode.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/node/PuppeteerNode.ts @@ -223,7 +223,7 @@ export class PuppeteerNode extends Puppeteer { * @internal */ get defaultDownloadPath(): string | undefined { - return this.configuration.downloadPath ?? this.configuration.cacheDirectory; + return this.configuration.cacheDirectory; } /** @@ -283,8 +283,7 @@ export class PuppeteerNode extends Puppeteer { throw new Error('The current platform is not supported.'); } - const cacheDir = - this.configuration.downloadPath ?? this.configuration.cacheDirectory!; + const cacheDir = this.configuration.cacheDirectory!; const installedBrowsers = await getInstalledBrowsers({ cacheDir, }); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/revisions.ts b/remote/test/puppeteer/packages/puppeteer-core/src/revisions.ts index 37360204d8..c543cd9517 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/revisions.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/revisions.ts @@ -8,7 +8,7 @@ * @internal */ export const PUPPETEER_REVISIONS = Object.freeze({ - chrome: '121.0.6167.85', - 'chrome-headless-shell': '121.0.6167.85', + chrome: '122.0.6261.94', + 'chrome-headless-shell': '122.0.6261.94', firefox: 'latest', }); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/util/Deferred.ts b/remote/test/puppeteer/packages/puppeteer-core/src/util/Deferred.ts index 0dfb013bb3..6699ace36d 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/util/Deferred.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/util/Deferred.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {TimeoutError} from '../common/Errors.js'; /** diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/util/Mutex.ts b/remote/test/puppeteer/packages/puppeteer-core/src/util/Mutex.ts index 9498bac306..f789837def 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/util/Mutex.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/util/Mutex.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {Deferred} from './Deferred.js'; import {disposeSymbol} from './disposable.js'; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.test.ts b/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.test.ts index 4cdaf15d5b..bc476b0153 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.test.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.test.ts @@ -9,7 +9,9 @@ import {describe, it} from 'node:test'; import expect from 'expect'; import sinon from 'sinon'; -import {invokeAtMostOnceForArguments} from './decorators.js'; +import {EventEmitter} from '../common/EventEmitter.js'; + +import {bubble, invokeAtMostOnceForArguments} from './decorators.js'; describe('decorators', function () { describe('invokeAtMostOnceForArguments', () => { @@ -76,4 +78,48 @@ describe('decorators', function () { }).toThrow(); }); }); + + describe('bubble', () => { + it('should work', () => { + class Test extends EventEmitter<any> { + @bubble() + accessor field = new EventEmitter(); + } + + const t = new Test(); + let a = false; + t.on('a', (value: boolean) => { + a = value; + }); + + t.field.emit('a', true); + expect(a).toBeTruthy(); + + // Set a new emitter. + t.field = new EventEmitter(); + a = false; + + t.field.emit('a', true); + expect(a).toBeTruthy(); + }); + + it('should not bubble down', () => { + class Test extends EventEmitter<any> { + @bubble() + accessor field = new EventEmitter<any>(); + } + + const t = new Test(); + let a = false; + t.field.on('a', (value: boolean) => { + a = value; + }); + + t.emit('a', true); + expect(a).toBeFalsy(); + + t.field.emit('a', true); + expect(a).toBeTruthy(); + }); + }); }); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts b/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts index af21c5fe29..c4dc3b6c0d 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +import type {EventType} from '../common/EventEmitter.js'; +import type {EventEmitter} from '../common/EventEmitter.js'; import type {Disposed, Moveable} from '../common/types.js'; import {asyncDisposeSymbol, disposeSymbol} from './disposable.js'; @@ -138,3 +140,67 @@ export function guarded<T extends object>( }; }; } + +const bubbleHandlers = new WeakMap<object, Map<any, any>>(); + +/** + * Event emitter fields marked with `bubble` will have their events bubble up + * the field owner. + */ +// The type is too complicated to type. +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types +export function bubble<T extends EventType[]>(events?: T) { + return <This extends EventEmitter<any>, Value extends EventEmitter<any>>( + {set, get}: ClassAccessorDecoratorTarget<This, Value>, + context: ClassAccessorDecoratorContext<This, Value> + ): ClassAccessorDecoratorResult<This, Value> => { + context.addInitializer(function () { + const handlers = bubbleHandlers.get(this) ?? new Map(); + if (handlers.has(events)) { + return; + } + + const handler = + events !== undefined + ? (type: EventType, event: unknown) => { + if (events.includes(type)) { + this.emit(type, event); + } + } + : (type: EventType, event: unknown) => { + this.emit(type, event); + }; + + handlers.set(events, handler); + bubbleHandlers.set(this, handlers); + }); + return { + set(emitter) { + const handler = bubbleHandlers.get(this)!.get(events)!; + + // In case we are re-setting. + const oldEmitter = get.call(this); + if (oldEmitter !== undefined) { + oldEmitter.off('*', handler); + } + + if (emitter === undefined) { + return; + } + emitter.on('*', handler); + set.call(this, emitter); + }, + // @ts-expect-error -- TypeScript incorrectly types init to require a + // return. + init(emitter) { + if (emitter === undefined) { + return; + } + const handler = bubbleHandlers.get(this)!.get(events)!; + + emitter.on('*', handler); + return emitter; + }, + }; + }; +} diff --git a/remote/test/puppeteer/packages/puppeteer-core/third_party/mitt/mitt.ts b/remote/test/puppeteer/packages/puppeteer-core/third_party/mitt/mitt.ts index c20aaa8342..1d522c780b 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/third_party/mitt/mitt.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/third_party/mitt/mitt.ts @@ -1,8 +1,3 @@ -/** - * @license - * Copyright 2022 Google Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - +// esline-disable rulesdir/check-license export * from 'mitt'; export {default as default} from 'mitt'; diff --git a/remote/test/puppeteer/packages/puppeteer-core/third_party/rxjs/rxjs.ts b/remote/test/puppeteer/packages/puppeteer-core/third_party/rxjs/rxjs.ts index b8b64788ae..6f4f844f5d 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/third_party/rxjs/rxjs.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/third_party/rxjs/rxjs.ts @@ -1,13 +1,11 @@ -/** - * @license - * Copyright 2023 Google Inc. - * SPDX-License-Identifier: Apache-2.0 - */ +// esline-disable rulesdir/check-license export { bufferCount, catchError, + combineLatest, concat, concatMap, + debounceTime, defaultIfEmpty, defer, delay, @@ -16,6 +14,7 @@ export { first, firstValueFrom, forkJoin, + delayWhen, from, fromEvent, identity, @@ -24,6 +23,7 @@ export { map, merge, mergeMap, + mergeScan, NEVER, noop, Observable, @@ -31,9 +31,11 @@ export { pipe, race, raceWith, + ReplaySubject, retry, startWith, switchMap, + take, takeUntil, tap, throwIfEmpty, @@ -42,20 +44,3 @@ export { } from 'rxjs'; export type * from 'rxjs'; - -import {filter, from, map, mergeMap, type Observable} from 'rxjs'; - -export function filterAsync<T>( - predicate: (value: T) => boolean | PromiseLike<boolean> -) { - return mergeMap<T, Observable<T>>(value => { - return from(Promise.resolve(predicate(value))).pipe( - filter(isMatch => { - return isMatch; - }), - map(() => { - return value; - }) - ); - }); -} diff --git a/remote/test/puppeteer/packages/puppeteer-core/third_party/tsconfig.json b/remote/test/puppeteer/packages/puppeteer-core/third_party/tsconfig.json index 25c438c57d..cfe3a26f4c 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/third_party/tsconfig.json +++ b/remote/test/puppeteer/packages/puppeteer-core/third_party/tsconfig.json @@ -3,6 +3,6 @@ "compilerOptions": { "declarationMap": false, "outDir": "../lib/esm/third_party", - "sourceMap": false, - }, + "sourceMap": false + } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/tsconfig.json b/remote/test/puppeteer/packages/puppeteer-core/tsconfig.json index b662532a01..a219f8b704 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/tsconfig.json +++ b/remote/test/puppeteer/packages/puppeteer-core/tsconfig.json @@ -3,6 +3,6 @@ "files": [], "references": [ {"path": "src/tsconfig.esm.json"}, - {"path": "src/tsconfig.cjs.json"}, - ], + {"path": "src/tsconfig.cjs.json"} + ] } diff --git a/remote/test/puppeteer/packages/puppeteer/CHANGELOG.md b/remote/test/puppeteer/packages/puppeteer/CHANGELOG.md index c3d834c5f5..8f98608527 100644 --- a/remote/test/puppeteer/packages/puppeteer/CHANGELOG.md +++ b/remote/test/puppeteer/packages/puppeteer/CHANGELOG.md @@ -29,6 +29,99 @@ All notable changes to this project will be documented in this file. See [standa * puppeteer-core bumped from 21.0.2 to 21.0.3 * @puppeteer/browsers bumped from 1.5.1 to 1.6.0 +## [22.4.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-v22.3.0...puppeteer-v22.4.0) (2024-03-05) + + +### Miscellaneous Chores + +* **puppeteer:** Synchronize puppeteer versions + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * puppeteer-core bumped from 22.3.0 to 22.4.0 + +## [22.3.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-v22.2.0...puppeteer-v22.3.0) (2024-02-25) + + +### Miscellaneous Chores + +* **puppeteer:** Synchronize puppeteer versions + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * puppeteer-core bumped from 22.2.0 to 22.3.0 + +## [22.2.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-v22.1.0...puppeteer-v22.2.0) (2024-02-21) + + +### Features + +* support local aliases when launching a browser ([#11947](https://github.com/puppeteer/puppeteer/issues/11947)) ([561e4cd](https://github.com/puppeteer/puppeteer/commit/561e4cd6ee79b19ac43f2c2fceaa1fce51052c02)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * puppeteer-core bumped from 22.1.0 to 22.2.0 + * @puppeteer/browsers bumped from 2.0.1 to 2.1.0 + +## [22.1.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-v22.0.0...puppeteer-v22.1.0) (2024-02-17) + + +### Miscellaneous Chores + +* **puppeteer:** Synchronize puppeteer versions + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * puppeteer-core bumped from 22.0.0 to 22.1.0 + * @puppeteer/browsers bumped from 2.0.0 to 2.0.1 + +## [22.0.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-v21.11.0...puppeteer-v22.0.0) (2024-02-05) + + +### âš BREAKING CHANGES + +* remove PUPPETEER_DOWNLOAD_PATH in favor of PUPPETEER_CACHE_DIR ([#11605](https://github.com/puppeteer/puppeteer/issues/11605)) +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) + +### Features + +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) ([953f420](https://github.com/puppeteer/puppeteer/commit/953f4207b17210fa7231225e6f29a826f77e0832)) +* remove PUPPETEER_DOWNLOAD_PATH in favor of PUPPETEER_CACHE_DIR ([#11605](https://github.com/puppeteer/puppeteer/issues/11605)) ([4677281](https://github.com/puppeteer/puppeteer/commit/467728187737283191f6528676e50d53dae6e5ef)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * puppeteer-core bumped from 21.11.0 to 22.0.0 + * @puppeteer/browsers bumped from 1.9.1 to 2.0.0 + +## [21.11.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-v21.10.0...puppeteer-v21.11.0) (2024-02-02) + + +### Features + +* implement boolean env vars ([#11811](https://github.com/puppeteer/puppeteer/issues/11811)) ([0a9f6d6](https://github.com/puppeteer/puppeteer/commit/0a9f6d670a86c6d1399501b2780fbb46cbe97b2c)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * puppeteer-core bumped from 21.10.0 to 21.11.0 + ## [21.10.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-v21.9.0...puppeteer-v21.10.0) (2024-01-29) diff --git a/remote/test/puppeteer/packages/puppeteer/package.json b/remote/test/puppeteer/packages/puppeteer/package.json index 0419e4b459..88637f3add 100644 --- a/remote/test/puppeteer/packages/puppeteer/package.json +++ b/remote/test/puppeteer/packages/puppeteer/package.json @@ -1,6 +1,6 @@ { "name": "puppeteer", - "version": "21.10.0", + "version": "22.4.0", "description": "A high-level API to control headless Chrome over the DevTools Protocol", "keywords": [ "puppeteer", @@ -32,12 +32,12 @@ "url": "https://github.com/puppeteer/puppeteer/tree/main/packages/puppeteer" }, "engines": { - "node": ">=16.13.2" + "node": ">=18" }, "scripts": { "build:docs": "wireit", "build": "wireit", - "clean": "../../tools/clean.js", + "clean": "../../tools/clean.mjs", "postinstall": "node install.mjs", "prepack": "wireit" }, @@ -124,8 +124,8 @@ "license": "Apache-2.0", "dependencies": { "cosmiconfig": "9.0.0", - "puppeteer-core": "21.10.0", - "@puppeteer/browsers": "1.9.1" + "puppeteer-core": "22.4.0", + "@puppeteer/browsers": "2.1.0" }, "devDependencies": { "@types/node": "18.17.15" diff --git a/remote/test/puppeteer/packages/puppeteer/src/getConfiguration.ts b/remote/test/puppeteer/packages/puppeteer/src/getConfiguration.ts index 28cf026eb7..6fd88678a4 100644 --- a/remote/test/puppeteer/packages/puppeteer/src/getConfiguration.ts +++ b/remote/test/puppeteer/packages/puppeteer/src/getConfiguration.ts @@ -10,6 +10,22 @@ import {join} from 'path'; import {cosmiconfigSync} from 'cosmiconfig'; import type {Configuration, Product} from 'puppeteer-core'; +function getBooleanEnvVar(name: string) { + const env = process.env[name]; + if (env === undefined) { + return; + } + switch (env.toLowerCase()) { + case '': + case '0': + case 'false': + case 'off': + return false; + default: + return true; + } +} + /** * @internal */ @@ -58,27 +74,29 @@ export const getConfiguration = (): Configuration => { // Set skipDownload explicitly or from default configuration.skipDownload = Boolean( - process.env['PUPPETEER_SKIP_DOWNLOAD'] ?? - process.env['npm_config_puppeteer_skip_download'] ?? - process.env['npm_package_config_puppeteer_skip_download'] ?? + getBooleanEnvVar('PUPPETEER_SKIP_DOWNLOAD') ?? + getBooleanEnvVar('npm_config_puppeteer_skip_download') ?? + getBooleanEnvVar('npm_package_config_puppeteer_skip_download') ?? configuration.skipDownload ); // Set skipChromeDownload explicitly or from default configuration.skipChromeDownload = Boolean( - process.env['PUPPETEER_SKIP_CHROME_DOWNLOAD'] ?? - process.env['npm_config_puppeteer_skip_chrome_download'] ?? - process.env['npm_package_config_puppeteer_skip_chrome_download'] ?? + getBooleanEnvVar('PUPPETEER_SKIP_CHROME_DOWNLOAD') ?? + getBooleanEnvVar('npm_config_puppeteer_skip_chrome_download') ?? + getBooleanEnvVar('npm_package_config_puppeteer_skip_chrome_download') ?? configuration.skipChromeDownload ); // Set skipChromeDownload explicitly or from default configuration.skipChromeHeadlessShellDownload = Boolean( - process.env['PUPPETEER_SKIP_CHROME_HEADLESS_SHELL_DOWNLOAD'] ?? - process.env['npm_config_puppeteer_skip_chrome_headless_shell_download'] ?? - process.env[ + getBooleanEnvVar('PUPPETEER_SKIP_CHROME_HEADLESS_SHELL_DOWNLOAD') ?? + getBooleanEnvVar( + 'npm_config_puppeteer_skip_chrome_headless_shell_download' + ) ?? + getBooleanEnvVar( 'npm_package_config_puppeteer_skip_chrome_headless_shell_download' - ] ?? + ) ?? configuration.skipChromeHeadlessShellDownload ); @@ -107,12 +125,6 @@ export const getConfiguration = (): Configuration => { process.env['npm_package_config_puppeteer_download_base_url'] ?? configuration.downloadBaseUrl ?? downloadHost; - - configuration.downloadPath = - process.env['PUPPETEER_DOWNLOAD_PATH'] ?? - process.env['npm_config_puppeteer_download_path'] ?? - process.env['npm_package_config_puppeteer_download_path'] ?? - configuration.downloadPath; } configuration.cacheDirectory = diff --git a/remote/test/puppeteer/packages/puppeteer/src/node/cli.ts b/remote/test/puppeteer/packages/puppeteer/src/node/cli.ts index 9a25c59327..39c1736e41 100644 --- a/remote/test/puppeteer/packages/puppeteer/src/node/cli.ts +++ b/remote/test/puppeteer/packages/puppeteer/src/node/cli.ts @@ -11,10 +11,7 @@ import {PUPPETEER_REVISIONS} from 'puppeteer-core/internal/revisions.js'; import puppeteer from '../puppeteer.js'; -// TODO: deprecate downloadPath in favour of cacheDirectory. -const cacheDir = - puppeteer.configuration.downloadPath ?? - puppeteer.configuration.cacheDirectory!; +const cacheDir = puppeteer.configuration.cacheDirectory!; void new CLI({ cachePath: cacheDir, diff --git a/remote/test/puppeteer/packages/puppeteer/src/node/install.ts b/remote/test/puppeteer/packages/puppeteer/src/node/install.ts index 76bad868b8..1af3105ee9 100644 --- a/remote/test/puppeteer/packages/puppeteer/src/node/install.ts +++ b/remote/test/puppeteer/packages/puppeteer/src/node/install.ts @@ -53,8 +53,7 @@ export async function downloadBrowser(): Promise<void> { PUPPETEER_REVISIONS['chrome-headless-shell'] || 'latest'; - // TODO: deprecate downloadPath in favour of cacheDirectory. - const cacheDir = configuration.downloadPath ?? configuration.cacheDirectory!; + const cacheDir = configuration.cacheDirectory!; try { const installationJobs = []; @@ -75,6 +74,8 @@ export async function downloadBrowser(): Promise<void> { buildId, downloadProgressCallback: makeProgressCallback(browser, buildId), baseUrl: downloadBaseUrl, + buildIdAlias: + buildId !== unresolvedBuildId ? unresolvedBuildId : undefined, }) .then(result => { logPolitely( @@ -113,6 +114,10 @@ export async function downloadBrowser(): Promise<void> { shellBuildId ), baseUrl: downloadBaseUrl, + buildIdAlias: + shellBuildId !== unresolvedShellBuildId + ? unresolvedShellBuildId + : undefined, }) .then(result => { logPolitely( diff --git a/remote/test/puppeteer/packages/puppeteer/tsconfig.json b/remote/test/puppeteer/packages/puppeteer/tsconfig.json index 11314a80e3..405998de4b 100644 --- a/remote/test/puppeteer/packages/puppeteer/tsconfig.json +++ b/remote/test/puppeteer/packages/puppeteer/tsconfig.json @@ -6,11 +6,11 @@ // just stick with ol'fashion path resolution. "baseUrl": ".", "paths": { - "puppeteer-core/internal/*": ["../puppeteer-core/lib/esm/puppeteer/*"], - }, + "puppeteer-core/internal/*": ["../puppeteer-core/lib/esm/puppeteer/*"] + } }, "references": [ {"path": "src/tsconfig.esm.json"}, - {"path": "src/tsconfig.cjs.json"}, - ], + {"path": "src/tsconfig.cjs.json"} + ] } diff --git a/remote/test/puppeteer/packages/testserver/package.json b/remote/test/puppeteer/packages/testserver/package.json index 3a9ecf9c65..a3a7ac7148 100644 --- a/remote/test/puppeteer/packages/testserver/package.json +++ b/remote/test/puppeteer/packages/testserver/package.json @@ -5,7 +5,7 @@ "main": "lib/index.js", "scripts": { "build": "wireit", - "clean": "../../tools/clean.js" + "clean": "../../tools/clean.mjs" }, "wireit": { "build": { diff --git a/remote/test/puppeteer/packages/testserver/src/index.ts b/remote/test/puppeteer/packages/testserver/src/index.ts index 2618fd4d0d..89439a08dd 100644 --- a/remote/test/puppeteer/packages/testserver/src/index.ts +++ b/remote/test/puppeteer/packages/testserver/src/index.ts @@ -98,6 +98,15 @@ export class TestServer { // Disable this as sometimes the socket will timeout // We rely on the fact that we will close the server at the end this.#server.keepAliveTimeout = 0; + this.#server.on('clientError', err => { + if ( + 'code' in err && + err.code === 'ERR_SSL_SSLV3_ALERT_CERTIFICATE_UNKNOWN' + ) { + return; + } + console.error('test-server client error', err); + }); this.#wsServer = new WebSocketServer({server: this.#server}); this.#wsServer.on('connection', this.#onWebSocketConnection); } diff --git a/remote/test/puppeteer/packages/testserver/tsconfig.json b/remote/test/puppeteer/packages/testserver/tsconfig.json index 08e6681481..6f0893ee41 100644 --- a/remote/test/puppeteer/packages/testserver/tsconfig.json +++ b/remote/test/puppeteer/packages/testserver/tsconfig.json @@ -6,7 +6,7 @@ "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "lib", - "rootDir": "src", + "rootDir": "src" }, - "include": ["src"], + "include": ["src"] } diff --git a/remote/test/puppeteer/test-d/CommonEventEmitter.test-d.ts b/remote/test/puppeteer/test-d/CommonEventEmitter.test-d.ts index 581b248b8a..40d0f9106b 100644 --- a/remote/test/puppeteer/test-d/CommonEventEmitter.test-d.ts +++ b/remote/test/puppeteer/test-d/CommonEventEmitter.test-d.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ // eslint-disable-next-line no-restricted-imports import {EventEmitter as NodeEventEmitter} from 'node:events'; diff --git a/remote/test/puppeteer/test-d/ElementHandle.test-d.ts b/remote/test/puppeteer/test-d/ElementHandle.test-d.ts index 469150933b..aa01ca2b28 100644 --- a/remote/test/puppeteer/test-d/ElementHandle.test-d.ts +++ b/remote/test/puppeteer/test-d/ElementHandle.test-d.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {expectNotType, expectType} from 'tsd'; import type {ElementHandle} from 'puppeteer'; diff --git a/remote/test/puppeteer/test-d/JSHandle.test-d.ts b/remote/test/puppeteer/test-d/JSHandle.test-d.ts index fa7348d28e..67a56760c2 100644 --- a/remote/test/puppeteer/test-d/JSHandle.test-d.ts +++ b/remote/test/puppeteer/test-d/JSHandle.test-d.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {expectNotAssignable, expectNotType, expectType} from 'tsd'; import type {ElementHandle, JSHandle} from 'puppeteer'; diff --git a/remote/test/puppeteer/test-d/NodeFor.test-d.ts b/remote/test/puppeteer/test-d/NodeFor.test-d.ts index 0a40b4e689..53487619e9 100644 --- a/remote/test/puppeteer/test-d/NodeFor.test-d.ts +++ b/remote/test/puppeteer/test-d/NodeFor.test-d.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {expectType, expectNotType} from 'tsd'; import type {NodeFor} from 'puppeteer'; diff --git a/remote/test/puppeteer/test-d/puppeteer.test-d.ts b/remote/test/puppeteer/test-d/puppeteer.test-d.ts index f7a45c0db4..66baff695a 100644 --- a/remote/test/puppeteer/test-d/puppeteer.test-d.ts +++ b/remote/test/puppeteer/test-d/puppeteer.test-d.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {expectType} from 'tsd'; import puppeteer, { diff --git a/remote/test/puppeteer/test/.eslintrc.js b/remote/test/puppeteer/test/.eslintrc.js index 489868b6ed..5f7746a76b 100644 --- a/remote/test/puppeteer/test/.eslintrc.js +++ b/remote/test/puppeteer/test/.eslintrc.js @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ module.exports = { rules: { 'no-restricted-imports': [ diff --git a/remote/test/puppeteer/test/TestExpectations.json b/remote/test/puppeteer/test/TestExpectations.json index f19c2f72e0..e55f223441 100644 --- a/remote/test/puppeteer/test/TestExpectations.json +++ b/remote/test/puppeteer/test/TestExpectations.json @@ -1,357 +1,255 @@ [ { - "testIdPattern": "*", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["SKIP", "TIMEOUT"] - }, - { - "testIdPattern": "[autofill.spec] *", + "testIdPattern": "[ariaqueryhandler.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome"], - "expectations": ["PASS"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[autofill.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[bfcache.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[chromiumonly.spec] Chromium-Specific Launcher tests *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[click.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[debugInfo.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[debugInfo.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[device-request-prompt.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[dialog.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[drag-and-drop.spec] *", + "testIdPattern": "[devtools.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[drag-and-drop.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[drag-and-drop.spec] Legacy Drag n' Drop *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[elementhandle.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[evaluation.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[fixtures.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[frame.spec] Frame specs *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[injected.spec] *", + "testIdPattern": "[extensions.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[jshandle.spec] *", + "testIdPattern": "[headful.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["headless", "firefox"], + "expectations": ["SKIP"], + "comment": "Cannot be run in headless mode" }, { - "testIdPattern": "[keyboard.spec] Keyboard *", + "testIdPattern": "[idle_override.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch *", - "platforms": ["darwin", "linux"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch *", "platforms": ["win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[locator.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[mouse.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[navigation.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[navigation.spec] navigation Page.goBack *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[network.spec] network *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.authenticate *", "platforms": ["darwin", "linux"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.authenticate *", "platforms": ["win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.setBypassServiceWorker *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.setBypassServiceWorker *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.setExtraHTTPHeaders *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.isNavigationRequest *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.buffer *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.json *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.text *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] - }, - { - "testIdPattern": "[page.spec] Page *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Popup *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[prerender.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[queryhandler.spec] *", + "testIdPattern": "[page.spec] Page Page.metrics *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[queryselector.spec] querySelector *", + "testIdPattern": "[pdf.spec] Page.pdf *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[screencast.spec] *", + "testIdPattern": "[proxy.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "Chrome-specific test" }, { - "testIdPattern": "[screenshot.spec] *", + "testIdPattern": "[requestinterception-experimental.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[screenshot.spec] Screenshots Cdp *", + "testIdPattern": "[requestinterception.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[stacktrace.spec] Stack trace *", + "testIdPattern": "[screencast.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] *", + "testIdPattern": "[screenshot.spec] Screenshots Cdp *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[accessibility.spec] *", + "testIdPattern": "[worker.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP", "TIMEOUT"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[accessibility.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[ariaqueryhandler.spec] *", - "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP", "TIMEOUT"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne (Chromium web test) *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler waitForSelector (aria) should have an error message specifically for awaiting an element to be hidden", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler waitForSelector (aria) should have correct stack trace for timeout", + "testIdPattern": "[accessibility.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler waitForSelector (aria) should respect timeout", + "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne (Chromium web test) should find by role \"button\"", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler waitForSelector (aria) should throw when frame is detached", + "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne (Chromium web test) should find by role \"heading\"", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[autofill.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "headless"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[browser.spec] Browser specs Browser.process should return child_process instance", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "chrome-headless-shell"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.target should return browser target", + "testIdPattern": "[browsercontext.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should be prompt by default", @@ -399,7 +297,8 @@ "testIdPattern": "[CDPSession.spec] Target.createCDPSession *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[CDPSession.spec] Target.createCDPSession should not report created targets for custom CDP sessions", @@ -411,343 +310,281 @@ "testIdPattern": "[chromiumonly.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[chromiumonly.spec] Chromium-Specific Launcher tests Puppeteer.launch |pipe| option *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[Connection.spec] WebDriver BiDi Connection should work", + "testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should delete cookie for specified URL regardless of the current page", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "The test relies on the default page partition key do not contain the source origin. This is not the case for Firefox." }, { "testIdPattern": "[coverage.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[coverage.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[coverage.spec] Coverage specs JSCoverage should ignore pptr internal scripts if reportAnonymousScripts is true", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools should expose DevTools as a page", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools should open devtools when \"devtools: true\" option is given", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools target.page() should return a DevTools page if asPage is used", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools target.page() should return a DevTools page if custom isPageTarget is provided", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[drag-and-drop.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.boundingBox should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["FAIL", "PASS"] - }, - { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should return Point data", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.clickablePoint should not work if the click box is not visible due to the iframe", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[emulation.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[emulation.spec] Emulation Page.viewport should get the proper viewport size", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[emulation.spec] Emulation Page.viewport should support mobile emulation", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should replace symbols with undefined", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should return properly serialize objects with unknown type fields", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should work for circular object", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluateOnNewDocument *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[evaluation.spec] Evaluation specs Page.removeScriptToEvaluateOnNewDocument *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[evaluation.spec] Evaluation specs Page.removeScriptToEvaluateOnNewDocument *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[fixtures.spec] Fixtures dumpio option should work with pipe option", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[frame.spec] Frame specs Frame Management should handle nested frames", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame.name()", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[frame.spec] Frame specs Frame Management should support lazy frames", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome"], - "expectations": ["FAIL", "PASS"] - }, - { - "testIdPattern": "[headful.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[idle_override.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[input.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[jshandle.spec] JSHandle JSHandle.jsonValue should not throw for circular objects", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[jshandle.spec] JSHandle JSHandle.jsonValue should work with dates", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[jshandle.spec] JSHandle Page.evaluateHandle should return the RemoteObject", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[jshandle.spec] JSHandle Page.evaluateHandle should use the same JS wrappers", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should send a character with sendCharacter in iframe", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect *", "platforms": ["win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject navigation when browser closes", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject waitForSelector when browser closes", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.executablePath returns executablePath for channel", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.executablePath should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.executablePath when executable path is configured its value is used", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch can launch and close the browser", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should be able to launch Chrome", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should be able to launch Firefox", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should have custom URL when launching browser", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should launch Chrome properly with --no-startup-window and waitForInitialPage=false", + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should work with no default arguments", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should work with no default arguments", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should work with no default arguments", - "platforms": ["linux"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should work with no default arguments", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch tmp profile should be cleaned up", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch userDataDir argument with non-existent dir", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[mouse.spec] Mouse should not throw if buttons are pressed twice", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[mouse.spec] Mouse should reset properly", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Frame.goto should return matching responses", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[navigation.spec] navigation Page.goto should fail when navigating to bad SSL", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should send referer", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.RequestFinished", @@ -765,19 +602,15 @@ "testIdPattern": "[network.spec] network Page.setBypassServiceWorker *", "platforms": ["win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[network.spec] network raw network headers Cross-origin set-cookie", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.initiator should return the initiator", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.isNavigationRequest should work", @@ -792,10 +625,18 @@ "expectations": ["PASS"] }, { + "testIdPattern": "[network.spec] network Request.postData should be |undefined| when there is no post data", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "Unsupported" + }, + { "testIdPattern": "[network.spec] network Request.postData should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.postData should work with blobs", @@ -808,127 +649,99 @@ "testIdPattern": "[network.spec] network Response.fromServiceWorker Response.fromServiceWorker", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.timing returns timing information", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[oopif.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF clickablePoint, boundingBox, boxModel should work for elements inside OOPIFs", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF should provide access to elements", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF should support evaluating in oop iframes", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF should support frames within OOP frames", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF should support frames within OOP iframes", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF should track navigations within OOP iframes", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF should treat OOP iframes and normal iframes the same", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF waitForFrame should resolve immediately if the frame already exists", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.addScriptTag should throw when added with content to the CSP page", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.addStyleTag should throw when added with content to the CSP page", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.bringToFront should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.close should *not* run beforeunload by default", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.close should *not* run beforeunload by default", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should have location when fetch fails", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.Events.Console should trigger correct Log", + "testIdPattern": "[page.spec] Page Page.Events.Console should return remote objects", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.Events.Console should work for different console API calls with logging functions", + "testIdPattern": "[page.spec] Page Page.Events.Console should return remote objects", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[page.spec] Page Page.Events.Console should trigger correct Log", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.error should throw when page crashes", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.exposeFunction *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.exposeFunction should work with loading frames", @@ -938,1762 +751,2086 @@ "comment": "Missing request interception" }, { - "testIdPattern": "[page.spec] Page Page.metrics metrics event fired on console.timeStamp", + "testIdPattern": "[page.spec] Page Page.pdf should respect timeout", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.metrics should get metrics from a page", + "testIdPattern": "[page.spec] Page Page.setBypassCSP *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.pdf can print to PDF with accessible", + "testIdPattern": "[page.spec] Page Page.setCacheEnabled should stay disabled when toggling request interception on/off", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.pdf should respect timeout", + "testIdPattern": "[page.spec] Page Page.setOfflineMode should emulate navigator.onLine", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox"], - "expectations": ["SKIP"] + "parameters": ["webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.removeExposedFunction should work", + "testIdPattern": "[page.spec] Page Page.setOfflineMode should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.setBypassCSP *", + "testIdPattern": "[page.spec] Page Page.setUserAgent *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.setCacheEnabled should stay disabled when toggling request interception on/off", + "testIdPattern": "[pdf.spec] Page.pdf *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.setGeolocation should work", + "testIdPattern": "[prerender.spec] Prerender can screencast", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.setOfflineMode should emulate navigator.onLine", + "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.setOfflineMode should work", + "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with name and role", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.setUserAgent *", + "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with role", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.waitForNetworkIdle should work with aborted requests", + "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work for ARIA selectors in multiple isolated worlds", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[prerender.spec] Prerender can screencast", + "testIdPattern": "[queryObjects.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[prerender.spec] Prerender can screencast", + "testIdPattern": "[requestinterception-experimental.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["new-headless"], - "expectations": ["FAIL", "PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL", "SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[proxy.spec] *", + "testIdPattern": "[requestinterception.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL", "SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[proxy.spec] request proxy in incognito browser context should respect proxy bypass list when configured at browser level", + "testIdPattern": "[screencast.spec] Screencasts Page.screencast should validate options", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], + "parameters": ["firefox"], "expectations": ["PASS"] }, { - "testIdPattern": "[proxy.spec] request proxy in incognito browser context should respect proxy bypass list when configured at context level", + "testIdPattern": "[screenshot.spec] Screenshots Cdp should work in \"fromSurface: false\" mode", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[proxy.spec] request proxy should respect proxy bypass list", + "testIdPattern": "[screenshot.spec] Screenshots Cdp should work in \"fromSurface: false\" mode", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["headless"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors", + "testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should get screenshot bigger than the viewport", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["cdp"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with name and role", + "testIdPattern": "[stacktrace.spec] Stack trace *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with role", + "testIdPattern": "[target.spec] Target Browser.waitForTarget should wait for a target", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] + "parameters": ["webDriverBiDi", "firefox"], + "expectations": ["FAIL", "PASS"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1882401" }, { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work for ARIA selectors in multiple isolated worlds", + "testIdPattern": "[target.spec] Target should close a service worker", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "not supported" }, { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work with :hover", + "testIdPattern": "[target.spec] Target should close a shared worker", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "not supported" }, { - "testIdPattern": "[queryhandler.spec] Query handler tests Text selectors in Page should clear caches", + "testIdPattern": "[TargetManager.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[queryObjects.spec] *", + "testIdPattern": "[TargetManager.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL", "SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[requestinterception-experimental.spec] *", + "testIdPattern": "[touchscreen.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[requestinterception.spec] *", + "testIdPattern": "[tracing.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[screencast.spec] *", + "testIdPattern": "[tracing.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[screencast.spec] Screencasts Page.screencast should validate options", + "testIdPattern": "[accessibility.spec] Accessibility get snapshots while the tree is re-calculated", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should get screenshot bigger than the viewport", + "testIdPattern": "[bfcache.spec] BFCache can navigate to a BFCached page containing an OOPIF and a worker", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp"], - "expectations": ["FAIL"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[stacktrace.spec] Stack trace *", + "testIdPattern": "[browser.spec] Browser specs Browser.isConnected should set the browser connected state", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target Browser.pages should return all of the pages", + "testIdPattern": "[browser.spec] Browser specs Browser.process should not return child_process for remote browser", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target Browser.targets should return all of the targets", + "testIdPattern": "[browser.spec] Browser specs Browser.userAgent should include Browser engine", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target Browser.waitForTarget should timeout waiting for a non-existent target", + "testIdPattern": "[browser.spec] Browser specs Browser.userAgent should include Browser engine", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should be able to use async waitForTarget", + "testIdPattern": "[browser.spec] Browser specs Browser.version should return version", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should be able to use the default page in the browser", + "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should deny permission when not listed", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should contain browser target", + "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should fail when bad permission is given", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], + "parameters": ["firefox", "webDriverBiDi"], "expectations": ["PASS"] }, { - "testIdPattern": "[target.spec] Target should not crash while redirecting if original request was missed", + "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should grant permission when listed", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should report when a new page is created and closed", + "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should grant persistent-storage", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should report when a target url changes", + "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should isolate permissions between browser contexts", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[TargetManager.spec] *", + "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should reset permissions", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[touchscreen.spec] *", + "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should trigger permission onchange", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[tracing.spec] *", + "testIdPattern": "[browsercontext.spec] BrowserContext should create new incognito context", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], + "parameters": ["firefox", "webDriverBiDi"], "expectations": ["PASS"] }, { - "testIdPattern": "[tracing.spec] *", + "testIdPattern": "[browsercontext.spec] BrowserContext should fire target events", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "In BiDi currently more events than needed are fired (because target is updated more often). We probably need to adjust the test as the behavior is not broken per se" }, { - "testIdPattern": "[worker.spec] *", + "testIdPattern": "[browsercontext.spec] BrowserContext should fire target events", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[accessibility.spec] Accessibility filtering children of leaf nodes rich text editable fields should have children", + "testIdPattern": "[browsercontext.spec] BrowserContext should have default context", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], + "parameters": ["firefox", "webDriverBiDi"], "expectations": ["PASS"] }, { - "testIdPattern": "[accessibility.spec] Accessibility get snapshots while the tree is re-calculated", + "testIdPattern": "[browsercontext.spec] BrowserContext should wait for a target", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler parseAriaSelector should find button", + "testIdPattern": "[browsercontext.spec] BrowserContext should work across sessions", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryAll should find menu by name", + "testIdPattern": "[CDPSession.spec] Target.createCDPSession should be able to detach session", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryAllArray $$eval should handle many elements", + "testIdPattern": "[CDPSession.spec] Target.createCDPSession should enable and disable domains independently", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne should find button by name and role", + "testIdPattern": "[CDPSession.spec] Target.createCDPSession should expose the underlying connection", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne should find button by role", + "testIdPattern": "[CDPSession.spec] Target.createCDPSession should respect custom timeout", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne should find by name", + "testIdPattern": "[CDPSession.spec] Target.createCDPSession should respect custom timeout", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne should find first matching element", + "testIdPattern": "[CDPSession.spec] Target.createCDPSession should send events", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[bfcache.spec] BFCache can navigate to a BFCached page containing an OOPIF and a worker", + "testIdPattern": "[chromiumonly.spec] Chromium-Specific Launcher tests Puppeteer.launch |browserURL| option should be able to connect using browserUrl, with and without trailing slash", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.isConnected should set the browser connected state", + "testIdPattern": "[chromiumonly.spec] Chromium-Specific Page Tests Page.setRequestInterception should work with intervention headers", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.isConnected should set the browser connected state", + "testIdPattern": "[chromiumonly.spec] Chromium-Specific Page Tests Page.setRequestInterception should work with intervention headers", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.isConnected should set the browser connected state", + "testIdPattern": "[click.spec] Page.click should click on checkbox label and toggle", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.process should not return child_process for remote browser", + "testIdPattern": "[click.spec] Page.click should click the button if window.Node is removed", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[click.spec] Page.click should click the button with deviceScaleFactor set", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.process should not return child_process for remote browser", + "testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.target should return browser target", + "testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.version should return version", + "testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "chrome"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should deny permission when not listed", + "testIdPattern": "[click.spec] Page.click should click with disabled javascript", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should grant permission when listed", + "testIdPattern": "[click.spec] Page.click should click with disabled javascript", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should grant persistent-storage", + "testIdPattern": "[click.spec] Page.click should scroll and click with disabled javascript", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should isolate permissions between browser contexts", + "testIdPattern": "[click.spec] Page.click should scroll and click with disabled javascript", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[click.spec] Page.click should select the text by triple clicking", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should reset permissions", + "testIdPattern": "[cookies.spec] Cookie specs Page.cookies should get cookies from nested path", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should trigger permission onchange", + "testIdPattern": "[cookies.spec] Cookie specs Page.cookies should not get cookies from not nested path", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should close all belonging targets once closing context", + "testIdPattern": "[cookies.spec] Cookie specs Page.cookies should not get cookies from subdomain", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should create new incognito context", + "testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should delete cookie", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should fire target events", + "testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should delete cookie", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "Not supported with cdp" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should provide a context id", + "testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should delete cookie for specified URL", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "Not supported with cdp" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should timeout waiting for a non-existent target", + "testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should not delete cookie for different domain", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should wait for a target", + "testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should not delete cookie for different domain", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "Not supported with cdp" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should wait for a target", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should default to setting secure cookie for HTTPS websites", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "Chromium-specific test. The test relies on the cookie in secure context to be secure. This is not the case for Firefox." }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should work across sessions", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should isolate cookies in browser contexts", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext window.open should use parent tab context", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set a cookie on a different domain", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should be able to detach session", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set a cookie with a path", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should be able to detach session", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set a cookie with a path", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should enable and disable domains independently", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set cookie with reasonable defaults", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should enable and disable domains independently", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set cookies from a frame", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should respect custom timeout", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set cookies from a frame", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should send events", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set multiple cookies", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should send events", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set multiple cookies", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should throw nice errors", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set secure same-site cookies from a frame", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "Chromium-specific test. The test relies on the cookie in secure context to be secure. This is not the case for Firefox." }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should work", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[chromiumonly.spec] Chromium-Specific Launcher tests Puppeteer.launch |browserURL| option should be able to connect using browserUrl, with and without trailing slash", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[click.spec] Page.click should click on checkbox input and toggle", + "testIdPattern": "[debugInfo.spec] DebugInfo Browser.debugInfo should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should click on checkbox label and toggle", + "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.cookies() should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "https://github.com/puppeteer/puppeteer/issues/12010" }, { - "testIdPattern": "[click.spec] Page.click should click the button if window.Node is removed", + "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.deleteCookie() should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should click the button inside an iframe", + "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.deleteCookie() should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[click.spec] Page.click should click the button with deviceScaleFactor set", + "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.setCookie() should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe", + "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.setCookie() should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe", + "testIdPattern": "[device-request-prompt.spec] device request prompt does not crash", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[dialog.spec] Page.Events.Dialog should allow accepting prompts", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe", + "testIdPattern": "[drag-and-drop.spec] Drag n' Drop should drag and drop", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should click with disabled javascript", + "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should return Point data", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should click with disabled javascript", + "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.isIntersectingViewport should work", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.isIntersectingViewport should work with svg elements", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[emulation.spec] Emulation Page.emulate should support clicking", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[emulation.spec] Emulation Page.emulate should support clicking", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should double click the button", + "testIdPattern": "[emulation.spec] Emulation Page.emulate should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should scroll and click with disabled javascript", + "testIdPattern": "[emulation.spec] Emulation Page.emulateCPUThrottling should change the CPU throttling rate successfully", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should scroll and click with disabled javascript", + "testIdPattern": "[emulation.spec] Emulation Page.emulateCPUThrottling should change the CPU throttling rate successfully", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should select the text by triple clicking", + "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaFeatures should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should select the text by triple clicking", + "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaFeatures should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.cookies should get cookies from multiple urls", + "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaType should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should work", + "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaType should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should default to setting secure cookie for HTTPS websites", + "testIdPattern": "[emulation.spec] Emulation Page.emulateNetworkConditions should change navigator.connection.effectiveType", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should isolate cookies in browser contexts", + "testIdPattern": "[emulation.spec] Emulation Page.emulateNetworkConditions should change navigator.connection.effectiveType", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set a cookie on a different domain", + "testIdPattern": "[emulation.spec] Emulation Page.emulateNetworkConditions should change navigator.connection.effectiveType", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set a cookie with a path", + "testIdPattern": "[emulation.spec] Emulation Page.emulateTimezone should throw for invalid timezone IDs", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set cookie with reasonable defaults", + "testIdPattern": "[emulation.spec] Emulation Page.emulateTimezone should throw for invalid timezone IDs", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set cookies from a frame", + "testIdPattern": "[emulation.spec] Emulation Page.emulateTimezone should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set multiple cookies", + "testIdPattern": "[emulation.spec] Emulation Page.emulateTimezone should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set secure same-site cookies from a frame", + "testIdPattern": "[emulation.spec] Emulation Page.emulateVisionDeficiency should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should work", + "testIdPattern": "[emulation.spec] Emulation Page.emulateVisionDeficiency should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[coverage.spec] Coverage specs CSSCoverage should work with complicated usecases", + "testIdPattern": "[emulation.spec] Emulation Page.viewport should be detectable by Modernizr", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[coverage.spec] Coverage specs JSCoverage should not ignore eval() scripts if reportAnonymousScripts is true", + "testIdPattern": "[emulation.spec] Emulation Page.viewport should detect touch when applying viewport with touches", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.cookies() should work", + "testIdPattern": "[emulation.spec] Emulation Page.viewport should load correct pictures when emulation dpr", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.deleteCookie() should work", + "testIdPattern": "[emulation.spec] Emulation Page.viewport should support landscape emulation", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.setCookie() should work", + "testIdPattern": "[emulation.spec] Emulation Page.viewport should support landscape emulation", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[dialog.spec] Page.Events.Dialog should allow accepting prompts", + "testIdPattern": "[emulation.spec] Emulation Page.viewport should support touch emulation", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[dialog.spec] Page.Events.Dialog should allow accepting prompts", + "testIdPattern": "[emulation.spec] Emulation Page.viewport should update media queries when resoltion changes", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[drag-and-drop.spec] Drag n' Drop should drag and drop", + "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should simulate a user gesture", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome"], - "expectations": ["FAIL"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.boundingBox should handle nested frames", + "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw when evaluation triggers reload", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.boundingBox should handle nested frames", + "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should work from-inside an exposed function", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.boxModel should work", + "testIdPattern": "[extensions.spec] extensions background_page target type should be available", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should return Point data", + "testIdPattern": "[extensions.spec] extensions service_worker target type should be available", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should return Point data", + "testIdPattern": "[extensions.spec] extensions target.page() should return a background_page", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.clickablePoint should work for iframes", + "testIdPattern": "[extensions.spec] extensions target.page() should return a background_page", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "chrome"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.clickablePoint should work for iframes", + "testIdPattern": "[fixtures.spec] Fixtures should close the browser when the node process closes", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.contentFrame should work", + "testIdPattern": "[frame.spec] Frame specs Frame Management should click elements in a frameset", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "New test for framesets (does not seem to pass in Firefox CDP)." }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.isIntersectingViewport should work", + "testIdPattern": "[frame.spec] Frame specs Frame Management should report different frame instance when frame re-attaches", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.isIntersectingViewport should work with svg elements", + "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame from-inside shadow DOM", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulate should support clicking", + "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame.name()", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateCPUThrottling should change the CPU throttling rate successfully", + "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame.parent()", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaFeatures should throw in case of bad argument", + "testIdPattern": "[frame.spec] Frame specs Frame Management should send events when frames are manipulated dynamically", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaFeatures should work", + "testIdPattern": "[frame.spec] Frame specs Frame Management should support lazy frames", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaType should throw in case of bad argument", + "testIdPattern": "[frame.spec] Frame specs Frame Management should support lazy frames", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaType should work", + "testIdPattern": "[frame.spec] Frame specs Frame.evaluate should throw for detached frames", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateNetworkConditions should change navigator.connection.effectiveType", + "testIdPattern": "[frame.spec] Frame specs Frame.executionContext should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateNetworkConditions should change navigator.connection.effectiveType", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails Network redirects should report SecurityDetails", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateTimezone should throw for invalid timezone IDs", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails Network redirects should report SecurityDetails", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateTimezone should work", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails Network redirects should report SecurityDetails", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateVisionDeficiency should throw for invalid vision deficiencies", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails should be |null| for non-secure requests", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateVisionDeficiency should work", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails should be |null| for non-secure requests", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.viewport should detect touch when applying viewport with touches", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.viewport should get the proper viewport size", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.viewport should support landscape emulation", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.viewport should support touch emulation", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work with request interception", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[evaluation.spec] Evaluation specs Frame.evaluate should have different execution contexts", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work with request interception", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should await promise", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work with request interception", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should simulate a user gesture", + "testIdPattern": "[input.spec] input tests FileChooser.accept should accept single file", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw if elementHandles are from other frames", + "testIdPattern": "[input.spec] input tests FileChooser.accept should accept single file", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw if elementHandles are from other frames", + "testIdPattern": "[input.spec] input tests FileChooser.accept should be able to read selected file", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw when evaluation triggers reload", + "testIdPattern": "[input.spec] input tests FileChooser.accept should be able to read selected file", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should work from-inside an exposed function", + "testIdPattern": "[input.spec] input tests FileChooser.accept should be able to reset selected files with empty file list", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[extensions.spec] extensions background_page target type should be available", + "testIdPattern": "[input.spec] input tests FileChooser.accept should be able to reset selected files with empty file list", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[extensions.spec] extensions service_worker target type should be available", + "testIdPattern": "[input.spec] input tests FileChooser.accept should error on read of non-existent files", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[extensions.spec] extensions target.page() should return a background_page", + "testIdPattern": "[input.spec] input tests FileChooser.accept should error on read of non-existent files", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[extensions.spec] extensions target.page() should return a background_page", + "testIdPattern": "[input.spec] input tests FileChooser.accept should fail when accepting file chooser twice", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[fixtures.spec] Fixtures should close the browser when the node process closes", + "testIdPattern": "[input.spec] input tests FileChooser.accept should fail when accepting file chooser twice", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should detach child frames on navigation", + "testIdPattern": "[input.spec] input tests FileChooser.accept should not accept multiple files for single-file input", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[input.spec] input tests FileChooser.accept should not accept multiple files for single-file input", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should report different frame instance when frame re-attaches", + "testIdPattern": "[input.spec] input tests FileChooser.accept should succeed even for non-existent files", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should report different frame instance when frame re-attaches", + "testIdPattern": "[input.spec] input tests FileChooser.accept should succeed even for non-existent files", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame from-inside shadow DOM", + "testIdPattern": "[input.spec] input tests FileChooser.cancel should cancel dialog", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame.name()", + "testIdPattern": "[input.spec] input tests FileChooser.cancel should cancel dialog", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame.parent()", + "testIdPattern": "[input.spec] input tests FileChooser.cancel should fail when canceling file chooser twice", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame.parent()", + "testIdPattern": "[input.spec] input tests FileChooser.cancel should fail when canceling file chooser twice", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should send events when frames are manipulated dynamically", + "testIdPattern": "[input.spec] input tests FileChooser.isMultiple should work for \"multiple\"", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should send events when frames are manipulated dynamically", + "testIdPattern": "[input.spec] input tests FileChooser.isMultiple should work for \"multiple\"", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[input.spec] input tests FileChooser.isMultiple should work for \"webkitdirectory\"", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should support framesets", + "testIdPattern": "[input.spec] input tests FileChooser.isMultiple should work for \"webkitdirectory\"", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should support lazy frames", + "testIdPattern": "[input.spec] input tests FileChooser.isMultiple should work for single file pick", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should support lazy frames", + "testIdPattern": "[input.spec] input tests FileChooser.isMultiple should work for single file pick", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame.evaluate should throw for detached frames", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should prioritize exact timeout over default timeout", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame.evaluate should throw for detached frames", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should prioritize exact timeout over default timeout", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame.executionContext should work", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should respect default timeout when there is no custom timeout", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails Network redirects should report SecurityDetails", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should respect default timeout when there is no custom timeout", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails should work", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should respect timeout", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should respect timeout", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should return the same file chooser when there are many watchdogs simultaneously", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should return the same file chooser when there are many watchdogs simultaneously", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should work when file input is attached to DOM", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work with mixed content", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should work when file input is attached to DOM", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work with mixed content", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should work when file input is not attached to DOM", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should work when file input is not attached to DOM", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work with mixed content", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should work with no timeout", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work with request interception", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should work with no timeout", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard ElementHandle.press should not support |text| option", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should report shiftKey", "platforms": ["darwin"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should send a character with sendCharacter", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should send a character with sendCharacter in iframe", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should specify location", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should specify repeat property", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should type all kinds of characters", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should type emoji", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should type emoji into an iframe", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[keyboard.spec] Keyboard should type emoji into an iframe", + "testIdPattern": "[launcher.spec] Launcher specs Browser target events should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Browser target events should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Browser target events should work", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Browser.Events.disconnected should be emitted when: browser gets closed, disconnected or underlying websocket gets closed", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Browser.Events.disconnected should be emitted when: browser gets closed, disconnected or underlying websocket gets closed", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.close should terminate network waiters", + "testIdPattern": "[launcher.spec] Launcher specs Browser.Events.disconnected should be emitted when: browser gets closed, disconnected or underlying websocket gets closed", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.close should terminate network waiters", "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject navigation when browser closes", + "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "https://github.com/puppeteer/puppeteer/issues/11849" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject navigation when browser closes", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject navigation when browser closes", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to close remote browser", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect multiple times to the same browser", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect to a browser with no page targets", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "chrome"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect to a browser with no page targets", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect to the same page simultaneously", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect to the same page simultaneously", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to reconnect", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to reconnect to a disconnected browser", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to reconnect to a disconnected browser", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to reconnect to a disconnected browser", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support ignoreHTTPSErrors option", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support ignoreHTTPSErrors option", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support targetFilter option", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support targetFilter option", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.executablePath returns executablePath for channel", + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support targetFilter option", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.executablePath should work", + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support targetFilter option in puppeteer.launch", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support targetFilter option in puppeteer.launch", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch can launch and close the browser", "platforms": ["win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should be able to launch Chrome", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should be able to launch Firefox", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should be able to launch Firefox", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "headless"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should close browser with beforeunload page", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should filter out ignored default argument in Firefox", "platforms": ["linux"], "parameters": ["firefox", "headful"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should filter out ignored default arguments in Chrome", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should have custom URL when launching browser", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch tmp profile should be cleaned up", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should have custom URL when launching browser", + "platforms": ["darwin"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "For some reason it times out on MacOS. Perhaps it's a bug in chromium-bidi" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch tmp profile should be cleaned up", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch userDataDir option should restore cookies", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[locator.spec] Locator Locator.click should work with a OOPIF", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[locator.spec] Locator Locator.click should work with a OOPIF", + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch tmp profile should be cleaned up", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[locator.spec] Locator Locator.race races multiple locators", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[mouse.spec] Mouse should send mouse wheel events", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[mouse.spec] Mouse should trigger hover state with removed window.Node", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Frame.goto should navigate subframes", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[navigation.spec] navigation Frame.goto should navigate subframes", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Frame.goto should reject when frame detaches", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Frame.goto should return matching responses", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation should fail when frame detaches", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation should fail when frame detaches", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation should work", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS", "TIMEOUT"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goBack should work with HistoryAPI", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[navigation.spec] navigation Page.goto should fail when main resources failed to load", + "testIdPattern": "[navigation.spec] navigation Page.goto should fail when navigating to bad SSL", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should fail when server returns 204", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to dataURL and fire dataURL requests", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to dataURL and fire dataURL requests", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to dataURL and fire dataURL requests", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to empty page with networkidle0", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to empty page with networkidle2", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to page with iframe and networkidle0", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to URL with hash and fire requests without hash", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to URL with hash and fire requests without hash", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should not leak listeners during navigation", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "PASS", "TIMEOUT"] - }, - { - "testIdPattern": "[navigation.spec] navigation Page.goto should not leak listeners during navigation of 11 pages", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[navigation.spec] navigation Page.goto should return response when page changes its URL after load", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should send referer", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should wait for network idle to succeed navigation", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should work when navigating to data url", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should work when navigating to data url", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should work when page calls history API in beforeunload", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[navigation.spec] navigation Page.goto should work with anchor navigation", - "platforms": ["linux"], - "parameters": ["chrome", "headless"], - "expectations": ["PASS", "TIMEOUT"] + "expectations": ["FAIL"], + "comment": "History navigation is breaking the Puppeteer expecation about navigation." }, { "testIdPattern": "[navigation.spec] navigation Page.goto should work with anchor navigation", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "headless"], - "expectations": ["PASS", "TIMEOUT"] + "parameters": ["chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should work with subframes return 204", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work when subframe issues window.stop()", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work when subframe issues window.stop()", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work when subframe issues window.stop()", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with DOM history.back()/history.forward()", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with history.pushState()", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with history.replaceState()", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "https://github.com/puppeteer/puppeteer/issues/11854" }, { "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with history.replaceState()", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.Request", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.Request", "platforms": ["win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.RequestFailed", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.RequestFinished", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.RequestServedFromCache", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.RequestServedFromCache", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.Response", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events should fire events in proper order", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events should fire events in proper order", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events should support redirects", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events should support redirects", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.authenticate should allow disable authentication", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.authenticate should fail if wrong credentials", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.authenticate should not disable caching", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.authenticate should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[network.spec] network Page.Events.Request should fire for iframes", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[network.spec] network Page.Events.Request should fire for iframes", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.setExtraHTTPHeaders should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie navigation", + "testIdPattern": "[network.spec] network raw network headers Cross-origin set-cookie", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie navigation", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie subresource", - "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie subresource", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie subresource", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie subresource", "platforms": ["win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] - }, - { - "testIdPattern": "[network.spec] network Request.frame should work for subframe navigation request", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[network.spec] network Request.frame should work for subframe navigation request", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.initiator should return the initiator", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.isNavigationRequest should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.isNavigationRequest should work with request interception", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.postData should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.postData should work with blobs", @@ -2706,529 +2843,561 @@ "testIdPattern": "[network.spec] network Response.buffer should throw if the response does not have a body", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[network.spec] network Response.buffer should throw if the response does not have a body", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.buffer should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.buffer should work with compression", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.fromCache should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.fromCache should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "Needs investigation, it looks like a bug in Puppeteer" }, { "testIdPattern": "[network.spec] network Response.fromCache should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.fromServiceWorker Response.fromServiceWorker", "platforms": ["win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.fromServiceWorker Response.fromServiceWorker", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[network.spec] network Response.headers should work", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.json should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.text should return uncompressed text", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.text should throw when requesting body of redirected response", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.text should wait until response completes", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.text should wait until response completes", "platforms": ["win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.text should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.timing returns timing information", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[oopif.spec] OOPIF clickablePoint, boundingBox, boxModel should work for elements inside OOPIFs", + "testIdPattern": "[oopif.spec] OOPIF should detect existing OOPIFs when Puppeteer connects to an existing page", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should expose events within OOPIFs", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should expose events within OOPIFs", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[oopif.spec] OOPIF should keep track of a frames OOP state", "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "Failed previously and currently times out" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should load oopif iframes with subresources and request interception", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should load oopif iframes with subresources and request interception", + "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should report google.com frame", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[oopif.spec] OOPIF should provide access to elements", + "testIdPattern": "[oopif.spec] OOPIF should report google.com frame", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[oopif.spec] OOPIF should support lazy OOP frames", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=187816" }, { - "testIdPattern": "[oopif.spec] OOPIF should support lazy OOP frames", + "testIdPattern": "[oopif.spec] OOPIF should support OOP iframes becoming normal iframes again", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[oopif.spec] OOPIF should support lazy OOP frames", + "testIdPattern": "[oopif.spec] OOPIF should support OOP iframes becoming normal iframes again", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should support OOP iframes getting detached", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should support OOP iframes getting detached", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should support wait for navigation for transitions from local to OOPIF", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[oopif.spec] OOPIF should support wait for navigation for transitions from local to OOPIF", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["PASS", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should support wait for navigation for transitions from local to OOPIF", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should wait for inner OOPIFs", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should wait for inner OOPIFs", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "Chrome-specific test (uses DNS mapping); does not work with Firefox." }, { "testIdPattern": "[page.spec] Page Page.addScriptTag should throw when added with content to the CSP page", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.addScriptTag should throw when added with content to the CSP page", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.bringToFront should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[page.spec] Page Page.client should return the client instance", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.close should reject all promises when page is closed", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.close should run beforeunload if asked for", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[page.spec] Page Page.close should run beforeunload if asked for", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.close should run beforeunload if asked for", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.close should terminate network waiters", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[page.spec] Page Page.Events.Console should have location and stack trace for console API calls", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should have location and stack trace for console API calls", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should have location and stack trace for console API calls", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should have location when fetch fails", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should not fail for window object", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should trigger correct Log", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should work for different console API calls with logging functions", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should work for different console API calls with timing functions", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.error should throw when page crashes", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Popup should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Popup should work with clicking target=_blank and rel=noopener", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Popup should work with clicking target=_blank and with rel=opener", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Popup should work with clicking target=_blank and without rel=opener", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Popup should work with fake-clicking target=_blank and rel=noopener", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Popup should work with noopener", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[page.spec] Page Page.exposeFunction should be callable from-inside evaluateOnNewDocument", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.metrics metrics event fired on console.timeStamp", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.metrics should get metrics from a page", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[page.spec] Page Page.pdf can print to PDF with accessible", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.removeExposedFunction should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.select should work when re-defining top-level Event class", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass after cross-process navigation", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass after cross-process navigation", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass CSP header", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass CSP header", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass CSP in iframes as well", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass CSP in iframes as well", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass CSP meta tag", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass CSP meta tag", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setCacheEnabled should enable or disable the cache based on the state passed", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setCacheEnabled should enable or disable the cache based on the state passed", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setCacheEnabled should stay disabled when toggling request interception on/off", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setGeolocation should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.setJavaScriptEnabled should work", + "testIdPattern": "[page.spec] Page Page.setGeolocation should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setJavaScriptEnabled should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setJavaScriptEnabled should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setOfflineMode should emulate navigator.onLine", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setOfflineMode should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setUserAgent should work with additional userAgentMetdata", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[prerender.spec] Prerender can navigate to a prerendered page via Puppeteer", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[prerender.spec] Prerender can screencast", + "testIdPattern": "[pdf.spec] Page.pdf can print to PDF with outline", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "headful"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[prerender.spec] Prerender via frame can navigate to a prerendered page via Puppeteer", + "testIdPattern": "[pdf.spec] Page.pdf can print to PDF with outline", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "headless"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[proxy.spec] request proxy in incognito browser context should proxy requests when configured at browser level", + "testIdPattern": "[proxy.spec] request proxy in incognito browser context should proxy requests when configured at context level", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: investigate" }, { "testIdPattern": "[proxy.spec] request proxy in incognito browser context should proxy requests when configured at context level", "platforms": ["win32"], "parameters": ["cdp", "chrome"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "Windows version of Chrome has a long-standing bug" }, { "testIdPattern": "[proxy.spec] request proxy in incognito browser context should proxy requests when configured at context level", "platforms": ["linux"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] - }, - { - "testIdPattern": "[proxy.spec] request proxy in incognito browser context should respect proxy bypass list when configured at browser level", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[proxy.spec] request proxy in incognito browser context should respect proxy bypass list when configured at context level", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[proxy.spec] request proxy should proxy requests when configured", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[proxy.spec] request proxy should respect proxy bypass list", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] - }, - { - "testIdPattern": "[proxy.spec] request proxy should respect proxy bypass list", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with name and role", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with role", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work for ARIA selectors in multiple isolated worlds", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[queryObjects.spec] page.queryObjects should fail for disposed handles", @@ -3246,469 +3415,524 @@ "testIdPattern": "[queryObjects.spec] page.queryObjects should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[queryObjects.spec] page.queryObjects should work for non-trivial page", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception-experimental.spec] request interception \"after each\" hook in \"request interception\"", "platforms": ["win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception-experimental.spec] request interception Page.setRequestInterception should load fonts if cache enabled", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["PASS", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception-experimental.spec] request interception Page.setRequestInterception should navigate to URL with hash and fire requests without hash", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception-experimental.spec] request interception Page.setRequestInterception should work with redirects", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception.spec] request interception Page.setRequestInterception should navigate to URL with hash and fire requests without hash", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots Cdp should use scale for clip", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should capture full element when larger than viewport", - "platforms": ["win32"], + "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work for an element with an offset", + "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work for an element with an offset", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work with a rotated element", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work with a rotated element", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should clip clip bigger than the viewport without \"captureBeyondViewport\"", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[stacktrace.spec] Stack trace should work for none error objects", + "testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should take fullPage screenshots", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target Browser.targets should return all of the targets", + "testIdPattern": "[stacktrace.spec] Stack trace should work for none error objects", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], + "parameters": ["cdp", "firefox"], "expectations": ["PASS"] }, { "testIdPattern": "[target.spec] Target Browser.waitForTarget should wait for a target", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target Browser.waitForTarget should wait for a target", + "testIdPattern": "[target.spec] Target should close a service worker", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "not supported" }, { - "testIdPattern": "[target.spec] Target should be able to use async waitForTarget", + "testIdPattern": "[target.spec] Target should close a shared worker", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "not supported" }, { - "testIdPattern": "[target.spec] Target should contain browser target", + "testIdPattern": "[target.spec] Target should create a worker from a service worker", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[target.spec] Target should create a worker from a service worker", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should create a worker from a shared worker", + "testIdPattern": "[target.spec] Target should create a worker from a service worker", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should have an opener", + "testIdPattern": "[target.spec] Target should create a worker from a shared worker", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should not crash while redirecting if original request was missed", + "testIdPattern": "[target.spec] Target should create a worker from a shared worker", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[target.spec] Target should not crash while redirecting if original request was missed", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should not report uninitialized pages", + "testIdPattern": "[target.spec] Target should create a worker from a shared worker", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should report when a new page is created and closed", + "testIdPattern": "[target.spec] Target should have an opener", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should report when a service worker is created and destroyed", + "testIdPattern": "[target.spec] Target should have an opener", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should report when a target url changes", + "testIdPattern": "[target.spec] Target should have an opener", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should report when a target url changes", + "testIdPattern": "[target.spec] Target should not crash while redirecting if original request was missed", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[touchscreen.spec] Touchscreen Touchscreen.prototype.touchMove should work", + "testIdPattern": "[target.spec] Target should not report uninitialized pages", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should survive cross-process navigation", + "testIdPattern": "[target.spec] Target should not report uninitialized pages", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should survive cross-process navigation", + "testIdPattern": "[target.spec] Target should report when a new page is created and closed", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should survive navigations", + "testIdPattern": "[target.spec] Target should report when a service worker is created and destroyed", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work when resolved right before execution context disposal", + "testIdPattern": "[target.spec] Target should report when a service worker is created and destroyed", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work with strict CSP policy", + "testIdPattern": "[target.spec] Target should report when a service worker is created and destroyed", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work with strict CSP policy", + "testIdPattern": "[target.spec] Target should report when a target url changes", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector Page.waitForSelector is shortcut for main frame", + "testIdPattern": "[TargetManager.spec] TargetManager should handle targets", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector Page.waitForSelector is shortcut for main frame", + "testIdPattern": "[touchscreen.spec] Touchscreen Touchscreen.prototype.tap should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should run in specified frame", + "testIdPattern": "[touchscreen.spec] Touchscreen Touchscreen.prototype.tap should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should run in specified frame", + "testIdPattern": "[touchscreen.spec] Touchscreen Touchscreen.prototype.touchMove should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation", + "testIdPattern": "[touchscreen.spec] Touchscreen Touchscreen.prototype.touchMove should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["TIMEOUT"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should survive cross-process navigation", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS", "TIMEOUT"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work when resolved right before execution context disposal", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should throw when frame is detached", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work with strict CSP policy", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should throw when frame is detached", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work with strict CSP policy", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should work with removed MutationObserver", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector Page.waitForSelector is shortcut for main frame", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForXPath should run in specified frame", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should run in specified frame", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForXPath should run in specified frame", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForXPath should throw when frame is detached", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForXPath should throw when frame is detached", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[worker.spec] Workers should report console logs", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should throw when frame is detached", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[worker.spec] Workers should report console logs", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should work with removed MutationObserver", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[worker.spec] Workers should report errors", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector xpath should run in specified frame", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[worker.spec] Workers should report errors", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector xpath should throw when frame is detached", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[worker.spec] Workers should report errors", + "testIdPattern": "[worker.spec] Workers can be closed", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[CDPSession.spec] Target.createCDPSession should send events", "platforms": ["win32"], - "parameters": ["cdp", "chrome", "new-headless"], - "expectations": ["FAIL", "PASS"] - }, - { - "testIdPattern": "[chromiumonly.spec] Chromium-Specific Launcher tests Puppeteer.launch |pipe| option should fire \"disconnected\" when closing with pipe", - "platforms": ["darwin"], - "parameters": ["cdp", "chrome", "new-headless"], - "expectations": ["FAIL"], - "comment": "Remove with M121" + "parameters": ["cdp", "chrome", "headless"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools should expose DevTools as a page", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools should open devtools when \"devtools: true\" option is given", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools target.page() should return a DevTools page if asPage is used", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools target.page() should return a DevTools page if custom isPageTarget is provided", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[extensions.spec] extensions background_page target type should be available", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[extensions.spec] extensions service_worker target type should be available", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[extensions.spec] extensions target.page() should return a background_page", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch userDataDir option restores preferences", "platforms": ["win32"], "parameters": ["firefox", "headless", "webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.Request", "platforms": ["linux"], - "parameters": ["cdp", "chrome", "new-headless"], - "expectations": ["FAIL", "PASS"] + "parameters": ["cdp", "chrome", "headless"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie subresource", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome", "headful"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.bringToFront should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception.spec] request interception Page.setRequestInterception should be abortable", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome", "headful"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception.spec] request interception Page.setRequestInterception should work with redirects", "platforms": ["win32"], - "parameters": ["cdp", "chrome", "new-headless"], - "expectations": ["FAIL", "PASS"] + "parameters": ["cdp", "chrome", "headless"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception.spec] request interception Page.setRequestInterception should work with redirects", "platforms": ["win32"], "parameters": ["cdp", "chrome", "headful"], - "expectations": ["FAIL", "PASS"] - }, - { - "testIdPattern": "[screenshot.spec] Screenshots Cdp should work in \"fromSurface: false\" mode", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "headless"], - "expectations": ["SKIP"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work for an element with an offset", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox", "headful"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work for an element with an offset", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox", "headless"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work with a rotated element", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox", "headful"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work with a rotated element", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox", "headless"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should take fullPage screenshots", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox", "headful"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should take fullPage screenshots", + "testIdPattern": "[target.spec] Target should close a service worker", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox", "headless"], - "expectations": ["FAIL"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "For some reason service_workers do not close in chrome-headless-shell" }, { "testIdPattern": "[worker.spec] Workers Page.workers", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["FAIL", "PASS"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" } ] diff --git a/remote/test/puppeteer/test/TestSuites.json b/remote/test/puppeteer/test/TestSuites.json index 32adc45d3c..3c36f8d7a4 100644 --- a/remote/test/puppeteer/test/TestSuites.json +++ b/remote/test/puppeteer/test/TestSuites.json @@ -13,9 +13,9 @@ "expectedLineCoverage": 93 }, { - "id": "chrome-new-headless", + "id": "chrome-headless-shell", "platforms": ["linux"], - "parameters": ["chrome", "new-headless", "cdp"], + "parameters": ["chrome", "chrome-headless-shell", "cdp"], "expectedLineCoverage": 93 }, { @@ -45,7 +45,7 @@ { "id": "chrome-bidi", "platforms": ["linux"], - "parameters": ["chrome", "headless", "webDriverBiDi"], + "parameters": ["chrome", "chrome-headless-shell", "webDriverBiDi"], "expectedLineCoverage": 56 } ], @@ -63,8 +63,8 @@ "headful": { "HEADLESS": "false" }, - "new-headless": { - "HEADLESS": "new" + "chrome-headless-shell": { + "HEADLESS": "shell" }, "webDriverBiDi": { "PUPPETEER_PROTOCOL": "webDriverBiDi" diff --git a/remote/test/puppeteer/test/assets/abort-request.html b/remote/test/puppeteer/test/assets/abort-request.html index 77c056a422..2977efa36f 100644 --- a/remote/test/puppeteer/test/assets/abort-request.html +++ b/remote/test/puppeteer/test/assets/abort-request.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <button id="abort"></button> <script> diff --git a/remote/test/puppeteer/test/assets/beforeunload.html b/remote/test/puppeteer/test/assets/beforeunload.html index 3cef6763f3..e6502a9ee1 100644 --- a/remote/test/puppeteer/test/assets/beforeunload.html +++ b/remote/test/puppeteer/test/assets/beforeunload.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <div>beforeunload demo.</div> <script> window.addEventListener('beforeunload', event => { diff --git a/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe-container.html b/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe-container.html index 857914bb6d..ce1fd52cff 100644 --- a/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe-container.html +++ b/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe-container.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <body>BFCached<a href="target.html">next</a></body> <script> window.addEventListener('DOMContentLoaded', () => { diff --git a/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe.html b/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe.html index 9233f557c5..b98b0a1ef8 100644 --- a/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe.html +++ b/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> const worker = new Worker('worker.mjs', {type: 'module'}) </script> diff --git a/remote/test/puppeteer/test/assets/cached/one-style-font.html b/remote/test/puppeteer/test/assets/cached/one-style-font.html index 8e7236dfb3..4afa507291 100644 --- a/remote/test/puppeteer/test/assets/cached/one-style-font.html +++ b/remote/test/puppeteer/test/assets/cached/one-style-font.html @@ -1,2 +1,3 @@ +<!DOCTYPE html> <link rel='stylesheet' href='./one-style-font.css'> <div>hello, world!</div> diff --git a/remote/test/puppeteer/test/assets/cached/one-style.html b/remote/test/puppeteer/test/assets/cached/one-style.html index 4760f2b9f7..b3a6eeeebe 100644 --- a/remote/test/puppeteer/test/assets/cached/one-style.html +++ b/remote/test/puppeteer/test/assets/cached/one-style.html @@ -1,2 +1,3 @@ +<!DOCTYPE html> <link rel='stylesheet' href='./one-style.css'> <div>hello, world!</div> diff --git a/remote/test/puppeteer/test/assets/csp.html b/remote/test/puppeteer/test/assets/csp.html index 34fc1fc1a5..4789cc21d3 100644 --- a/remote/test/puppeteer/test/assets/csp.html +++ b/remote/test/puppeteer/test/assets/csp.html @@ -1 +1,2 @@ +<!DOCTYPE html> <meta http-equiv="Content-Security-Policy" content="default-src 'self'"> diff --git a/remote/test/puppeteer/test/assets/csscoverage/empty.html b/remote/test/puppeteer/test/assets/csscoverage/empty.html index b3845c366d..eef2af1807 100644 --- a/remote/test/puppeteer/test/assets/csscoverage/empty.html +++ b/remote/test/puppeteer/test/assets/csscoverage/empty.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style></style> <div>empty style tag</div> diff --git a/remote/test/puppeteer/test/assets/csscoverage/involved.html b/remote/test/puppeteer/test/assets/csscoverage/involved.html index bcd9845b93..4b944ae7a8 100644 --- a/remote/test/puppeteer/test/assets/csscoverage/involved.html +++ b/remote/test/puppeteer/test/assets/csscoverage/involved.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> @charset "utf-8"; @namespace svg url(http://www.w3.org/2000/svg); diff --git a/remote/test/puppeteer/test/assets/csscoverage/media.html b/remote/test/puppeteer/test/assets/csscoverage/media.html index bfb89f8f75..57af00e2f6 100644 --- a/remote/test/puppeteer/test/assets/csscoverage/media.html +++ b/remote/test/puppeteer/test/assets/csscoverage/media.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> @media screen { div { color: green; } } </style> <div>hello, world</div> diff --git a/remote/test/puppeteer/test/assets/csscoverage/multiple.html b/remote/test/puppeteer/test/assets/csscoverage/multiple.html index 0fd97e962a..a1d57415f9 100644 --- a/remote/test/puppeteer/test/assets/csscoverage/multiple.html +++ b/remote/test/puppeteer/test/assets/csscoverage/multiple.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <link rel="stylesheet" href="stylesheet1.css"> <link rel="stylesheet" href="stylesheet2.css"> <script> diff --git a/remote/test/puppeteer/test/assets/csscoverage/simple.html b/remote/test/puppeteer/test/assets/csscoverage/simple.html index 3beae21829..f51dd11ac9 100644 --- a/remote/test/puppeteer/test/assets/csscoverage/simple.html +++ b/remote/test/puppeteer/test/assets/csscoverage/simple.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> div { color: green; } a { color: blue; } diff --git a/remote/test/puppeteer/test/assets/csscoverage/sourceurl.html b/remote/test/puppeteer/test/assets/csscoverage/sourceurl.html index df4e9c276c..592019fe1a 100644 --- a/remote/test/puppeteer/test/assets/csscoverage/sourceurl.html +++ b/remote/test/puppeteer/test/assets/csscoverage/sourceurl.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> body { padding: 10px; diff --git a/remote/test/puppeteer/test/assets/csscoverage/unused.html b/remote/test/puppeteer/test/assets/csscoverage/unused.html index 5b8186a3bf..2e8706cc31 100644 --- a/remote/test/puppeteer/test/assets/csscoverage/unused.html +++ b/remote/test/puppeteer/test/assets/csscoverage/unused.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> @media screen { a { color: green; } diff --git a/remote/test/puppeteer/test/assets/dynamic-oopif.html b/remote/test/puppeteer/test/assets/dynamic-oopif.html index 38614d0289..dbe93a9923 100644 --- a/remote/test/puppeteer/test/assets/dynamic-oopif.html +++ b/remote/test/puppeteer/test/assets/dynamic-oopif.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> window.addEventListener('DOMContentLoaded', () => { const iframe = document.createElement('iframe'); diff --git a/remote/test/puppeteer/test/assets/empty.html b/remote/test/puppeteer/test/assets/empty.html index e69de29bb2..763b0739be 100644 --- a/remote/test/puppeteer/test/assets/empty.html +++ b/remote/test/puppeteer/test/assets/empty.html @@ -0,0 +1 @@ +<!DOCTYPE html>
\ No newline at end of file diff --git a/remote/test/puppeteer/test/assets/error.html b/remote/test/puppeteer/test/assets/error.html index 130400c006..6929791e11 100644 --- a/remote/test/puppeteer/test/assets/error.html +++ b/remote/test/puppeteer/test/assets/error.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> a(); diff --git a/remote/test/puppeteer/test/assets/frames/frame.html b/remote/test/puppeteer/test/assets/frames/frame.html index 8f20d2da9f..29e7426dbc 100644 --- a/remote/test/puppeteer/test/assets/frames/frame.html +++ b/remote/test/puppeteer/test/assets/frames/frame.html @@ -1,8 +1,11 @@ +<!DOCTYPE html> <link rel='stylesheet' href='./style.css'> <script src='./script.js' type='text/javascript'></script> <style> div { line-height: 18px; + width: 300px; + box-sizing: border-box; } </style> <div>Hi, I'm frame</div> diff --git a/remote/test/puppeteer/test/assets/frames/frameset.html b/remote/test/puppeteer/test/assets/frames/frameset.html index 4d56f88839..7ef2faaa8d 100644 --- a/remote/test/puppeteer/test/assets/frames/frameset.html +++ b/remote/test/puppeteer/test/assets/frames/frameset.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <frameset> <frameset> <frame src='./frame.html'></frame> diff --git a/remote/test/puppeteer/test/assets/frames/lazy-frame.html b/remote/test/puppeteer/test/assets/frames/lazy-frame.html index 4821cd76cd..45f9be020b 100644 --- a/remote/test/puppeteer/test/assets/frames/lazy-frame.html +++ b/remote/test/puppeteer/test/assets/frames/lazy-frame.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <iframe width="100%" height="300" src="about:blank"></iframe> <div style="height: 800vh"></div> <iframe width="100%" height="300" src='./frame.html' loading="lazy"></iframe>
\ No newline at end of file diff --git a/remote/test/puppeteer/test/assets/frames/nested-frames.html b/remote/test/puppeteer/test/assets/frames/nested-frames.html index e9c5d83c03..331462afe8 100644 --- a/remote/test/puppeteer/test/assets/frames/nested-frames.html +++ b/remote/test/puppeteer/test/assets/frames/nested-frames.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> :root { scrollbar-width: none; diff --git a/remote/test/puppeteer/test/assets/frames/one-frame-url-fragment.html b/remote/test/puppeteer/test/assets/frames/one-frame-url-fragment.html index d1462641ff..bc2266ad78 100644 --- a/remote/test/puppeteer/test/assets/frames/one-frame-url-fragment.html +++ b/remote/test/puppeteer/test/assets/frames/one-frame-url-fragment.html @@ -1 +1,2 @@ +<!DOCTYPE html> <iframe src='./frame.html?param=value#fragment'></iframe> diff --git a/remote/test/puppeteer/test/assets/frames/one-frame.html b/remote/test/puppeteer/test/assets/frames/one-frame.html index e941d795a2..d520733f5c 100644 --- a/remote/test/puppeteer/test/assets/frames/one-frame.html +++ b/remote/test/puppeteer/test/assets/frames/one-frame.html @@ -1 +1,2 @@ +<!DOCTYPE html> <iframe src='./frame.html'></iframe> diff --git a/remote/test/puppeteer/test/assets/frames/two-frames.html b/remote/test/puppeteer/test/assets/frames/two-frames.html index b2ee853eda..9c7a6cbca1 100644 --- a/remote/test/puppeteer/test/assets/frames/two-frames.html +++ b/remote/test/puppeteer/test/assets/frames/two-frames.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> body { display: flex; diff --git a/remote/test/puppeteer/test/assets/global-var.html b/remote/test/puppeteer/test/assets/global-var.html index b6be975038..37ab45f9c3 100644 --- a/remote/test/puppeteer/test/assets/global-var.html +++ b/remote/test/puppeteer/test/assets/global-var.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> var globalVar = 123; </script>
\ No newline at end of file diff --git a/remote/test/puppeteer/test/assets/grid.html b/remote/test/puppeteer/test/assets/grid.html index 437193573d..f5d4ea6d60 100644 --- a/remote/test/puppeteer/test/assets/grid.html +++ b/remote/test/puppeteer/test/assets/grid.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> document.addEventListener('DOMContentLoaded', function() { function generatePalette(amount) { diff --git a/remote/test/puppeteer/test/assets/historyapi.html b/remote/test/puppeteer/test/assets/historyapi.html index bacaf9e9a0..cea5cbdab1 100644 --- a/remote/test/puppeteer/test/assets/historyapi.html +++ b/remote/test/puppeteer/test/assets/historyapi.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> window.addEventListener('DOMContentLoaded', () => { history.pushState({}, '', '#1'); diff --git a/remote/test/puppeteer/test/assets/initiator.html b/remote/test/puppeteer/test/assets/initiator.html index 12889d3242..df88f5e954 100644 --- a/remote/test/puppeteer/test/assets/initiator.html +++ b/remote/test/puppeteer/test/assets/initiator.html @@ -1,2 +1,3 @@ +<!DOCTYPE html> <iframe src="./frames/frame.html"></iframe> <script src="./initiator.js"></script> diff --git a/remote/test/puppeteer/test/assets/inner-frame1.html b/remote/test/puppeteer/test/assets/inner-frame1.html index 00f19ec166..becdb4a466 100644 --- a/remote/test/puppeteer/test/assets/inner-frame1.html +++ b/remote/test/puppeteer/test/assets/inner-frame1.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> window.addEventListener('DOMContentLoaded', () => { const iframe = document.createElement('iframe'); diff --git a/remote/test/puppeteer/test/assets/inner-frame2.html b/remote/test/puppeteer/test/assets/inner-frame2.html index 9a236cc48f..39dcf4c25c 100644 --- a/remote/test/puppeteer/test/assets/inner-frame2.html +++ b/remote/test/puppeteer/test/assets/inner-frame2.html @@ -1 +1,2 @@ +<!DOCTYPE html> <button>click</button> diff --git a/remote/test/puppeteer/test/assets/input/touchscreen.html b/remote/test/puppeteer/test/assets/input/touchscreen.html index 76e31c97f9..b3a51e7f91 100644 --- a/remote/test/puppeteer/test/assets/input/touchscreen.html +++ b/remote/test/puppeteer/test/assets/input/touchscreen.html @@ -1,10 +1,10 @@ -<!doctype html> +<!DOCTYPE html> <html> <head> <title>Touch test</title> </head> - <body> + <body style="touch-action: none"> <style> button { box-sizing: border-box; @@ -20,103 +20,53 @@ <button>Click target</button> <script> var allEvents = []; - globalThis.addEventListener( - "touchstart", - (event) => { - allEvents.push({ - type: "touchstart", - touches: [...event.changedTouches].map((touch) => [ - touch.clientX, - touch.clientY, - touch.radiusX, - touch.radiusY, - ]), - }); - }, - true, - ); - globalThis.addEventListener( - "touchmove", - (event) => { - allEvents.push({ - type: "touchmove", - touches: [...event.changedTouches].map((touch) => [ - touch.clientX, - touch.clientY, - touch.radiusX, - touch.radiusY, - ]), - }); - }, - true, - ); - globalThis.addEventListener( - "touchend", - (event) => { - allEvents.push({ - type: "touchend", - touches: [...event.changedTouches].map((touch) => [ - touch.clientX, - touch.clientY, - touch.radiusX, - touch.radiusY, - ]) - }); - }, - true, - ); - globalThis.addEventListener( - "pointerdown", - (event) => { - allEvents.push({ - type: "pointerdown", - x: event.x, - y: event.y, - width: event.width, - height: event.height, - }); - }, - true, - ); - globalThis.addEventListener( - "pointermove", - (event) => { - allEvents.push({ - type: "pointermove", - x: event.x, - y: event.y, - width: event.width, - height: event.height, - }); - }, - true, - ); - globalThis.addEventListener( - "pointerup", - (event) => { - allEvents.push({ - type: "pointerup", - x: event.x, - y: event.y, - width: event.width, - height: event.height, - }); - }, - true, - ); - globalThis.addEventListener( - "click", - (event) => { - allEvents.push({ - type: "click", - x: event.x, - y: event.y, - width: event.width, - height: event.height, - }); - }, - true, - ); + for (const name of ["touchstart", "touchmove", "touchend"]) { + globalThis.addEventListener( + name, + (event) => { + allEvents.push({ + type: name, + changedTouches: [...event.changedTouches].map((touch) => ({ + clientX: touch.clientX, + clientY: touch.clientY, + radiusX: touch.radiusX, + radiusY: touch.radiusY, + force: touch.force, + })), + activeTouches: [...event.touches].map((touch) => ({ + clientX: touch.clientX, + clientY: touch.clientY, + radiusX: touch.radiusX, + radiusY: touch.radiusY, + force: touch.force, + })), + }); + }, + true, + ); + } + for (const name of ['pointerdown', 'pointermove', 'pointerup', 'click']) { + globalThis.addEventListener( + name, + (event) => { + allEvents.push({ + type: name, + x: event.x, + y: event.y, + width: event.width, + height: event.height, + altitudeAngle: event.altitudeAngle, + azimuthAngle: event.azimuthAngle, + pressure: event.pressure, + pointerType: event.pointerType, + twist: event.twist, + tiltX: event.tiltX, + tiltY: event.tiltY, + }); + }, + true, + ); + } </script> </body> </html> diff --git a/remote/test/puppeteer/test/assets/jscoverage/eval.html b/remote/test/puppeteer/test/assets/jscoverage/eval.html index 838ae28763..dadc7d7b02 100644 --- a/remote/test/puppeteer/test/assets/jscoverage/eval.html +++ b/remote/test/puppeteer/test/assets/jscoverage/eval.html @@ -1 +1,2 @@ +<!DOCTYPE html> <script>eval('console.log("foo")')</script> diff --git a/remote/test/puppeteer/test/assets/jscoverage/involved.html b/remote/test/puppeteer/test/assets/jscoverage/involved.html index fcc32ba2ca..c900801860 100644 --- a/remote/test/puppeteer/test/assets/jscoverage/involved.html +++ b/remote/test/puppeteer/test/assets/jscoverage/involved.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> function foo() { if (1 > 2) diff --git a/remote/test/puppeteer/test/assets/jscoverage/multiple.html b/remote/test/puppeteer/test/assets/jscoverage/multiple.html index bdef59885b..683e10b99d 100644 --- a/remote/test/puppeteer/test/assets/jscoverage/multiple.html +++ b/remote/test/puppeteer/test/assets/jscoverage/multiple.html @@ -1,2 +1,3 @@ +<!DOCTYPE html> <script src='script1.js'></script> <script src='script2.js'></script> diff --git a/remote/test/puppeteer/test/assets/jscoverage/ranges.html b/remote/test/puppeteer/test/assets/jscoverage/ranges.html index 3d02670aea..2535e740d7 100644 --- a/remote/test/puppeteer/test/assets/jscoverage/ranges.html +++ b/remote/test/puppeteer/test/assets/jscoverage/ranges.html @@ -1,2 +1,3 @@ +<!DOCTYPE html> <script> function unused(){}console.log('used!');if(true===false)console.log('unused!');</script> diff --git a/remote/test/puppeteer/test/assets/jscoverage/simple.html b/remote/test/puppeteer/test/assets/jscoverage/simple.html index 49eeeea6ae..9694f57d3e 100644 --- a/remote/test/puppeteer/test/assets/jscoverage/simple.html +++ b/remote/test/puppeteer/test/assets/jscoverage/simple.html @@ -1,2 +1,3 @@ +<!DOCTYPE html> <script> function foo() {function bar() { } console.log(1); } foo(); </script> diff --git a/remote/test/puppeteer/test/assets/jscoverage/sourceurl.html b/remote/test/puppeteer/test/assets/jscoverage/sourceurl.html index e477750320..c3c5251ad3 100644 --- a/remote/test/puppeteer/test/assets/jscoverage/sourceurl.html +++ b/remote/test/puppeteer/test/assets/jscoverage/sourceurl.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> console.log(1); //# sourceURL=nicename.js diff --git a/remote/test/puppeteer/test/assets/jscoverage/unused.html b/remote/test/puppeteer/test/assets/jscoverage/unused.html index 59c4a5a70b..80db364242 100644 --- a/remote/test/puppeteer/test/assets/jscoverage/unused.html +++ b/remote/test/puppeteer/test/assets/jscoverage/unused.html @@ -1 +1,2 @@ +<!DOCTYPE html> <script>function foo() { }</script> diff --git a/remote/test/puppeteer/test/assets/lazy-oopif-frame.html b/remote/test/puppeteer/test/assets/lazy-oopif-frame.html index 83a420d029..71d00a3f72 100644 --- a/remote/test/puppeteer/test/assets/lazy-oopif-frame.html +++ b/remote/test/puppeteer/test/assets/lazy-oopif-frame.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <iframe width="100%" height="300" src="about:blank"></iframe> <div style="height: 800vh"></div> <iframe width="100%" height="300" src="https://www.example.com" loading="lazy"></iframe> diff --git a/remote/test/puppeteer/test/assets/main-frame.html b/remote/test/puppeteer/test/assets/main-frame.html index 0c50feff85..ce223b5c2a 100644 --- a/remote/test/puppeteer/test/assets/main-frame.html +++ b/remote/test/puppeteer/test/assets/main-frame.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> window.addEventListener('DOMContentLoaded', () => { const iframe = document.createElement('iframe'); diff --git a/remote/test/puppeteer/test/assets/mobile.html b/remote/test/puppeteer/test/assets/mobile.html index 8e94b2fe29..427cf74aa5 100644 --- a/remote/test/puppeteer/test/assets/mobile.html +++ b/remote/test/puppeteer/test/assets/mobile.html @@ -1 +1,2 @@ +<!DOCTYPE html> <meta name = "viewport" content = "initial-scale = 1, user-scalable = no"> diff --git a/remote/test/puppeteer/test/assets/networkidle.html b/remote/test/puppeteer/test/assets/networkidle.html index 910ae1736d..cbe0e153d0 100644 --- a/remote/test/puppeteer/test/assets/networkidle.html +++ b/remote/test/puppeteer/test/assets/networkidle.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> async function sleep(delay) { return new Promise(resolve => setTimeout(resolve, delay)); diff --git a/remote/test/puppeteer/test/assets/one-style.html b/remote/test/puppeteer/test/assets/one-style.html index 4760f2b9f7..b3a6eeeebe 100644 --- a/remote/test/puppeteer/test/assets/one-style.html +++ b/remote/test/puppeteer/test/assets/one-style.html @@ -1,2 +1,3 @@ +<!DOCTYPE html> <link rel='stylesheet' href='./one-style.css'> <div>hello, world!</div> diff --git a/remote/test/puppeteer/test/assets/oopif.html b/remote/test/puppeteer/test/assets/oopif.html index f04b9127af..39e35eea96 100644 --- a/remote/test/puppeteer/test/assets/oopif.html +++ b/remote/test/puppeteer/test/assets/oopif.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <a id="navigate-within-document" href="#nav">Navigate within document</a> <a name="nav"></a> <script> diff --git a/remote/test/puppeteer/test/assets/p-selectors.html b/remote/test/puppeteer/test/assets/p-selectors.html index 24900623d8..e442a53d88 100644 --- a/remote/test/puppeteer/test/assets/p-selectors.html +++ b/remote/test/puppeteer/test/assets/p-selectors.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <div id="a">hello <button id="b">world</button> <span id="f"></span> <div id="c"></div> diff --git a/remote/test/puppeteer/test/assets/pdf.html b/remote/test/puppeteer/test/assets/pdf.html index 987df27ebe..ef046e3d36 100644 --- a/remote/test/puppeteer/test/assets/pdf.html +++ b/remote/test/puppeteer/test/assets/pdf.html @@ -6,6 +6,12 @@ <title>PDF</title> </head> <body> - <div>PDF Content</div> + <h1>PDF Content</h1> + <section> + <h1>PDF Subcontent 1</h1> + </section> + <section> + <h1>PDF Subcontent 2</h1> + </section> </body> </html> diff --git a/remote/test/puppeteer/test/assets/resetcss.html b/remote/test/puppeteer/test/assets/resetcss.html index e4e04b1f8a..7e020d6ed2 100644 --- a/remote/test/puppeteer/test/assets/resetcss.html +++ b/remote/test/puppeteer/test/assets/resetcss.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 diff --git a/remote/test/puppeteer/test/assets/self-request.html b/remote/test/puppeteer/test/assets/self-request.html index 88aff620ff..682c326412 100644 --- a/remote/test/puppeteer/test/assets/self-request.html +++ b/remote/test/puppeteer/test/assets/self-request.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> var req = new XMLHttpRequest(); req.open('GET', '/self-request.html'); diff --git a/remote/test/puppeteer/test/assets/serviceworkers/empty/sw.html b/remote/test/puppeteer/test/assets/serviceworkers/empty/sw.html index bef85d985b..21e9d5dbd4 100644 --- a/remote/test/puppeteer/test/assets/serviceworkers/empty/sw.html +++ b/remote/test/puppeteer/test/assets/serviceworkers/empty/sw.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> window.registrationPromise = navigator.serviceWorker.register('sw.js'); </script> diff --git a/remote/test/puppeteer/test/assets/serviceworkers/fetch/sw.html b/remote/test/puppeteer/test/assets/serviceworkers/fetch/sw.html index a9d28acb09..c9a918c2d9 100644 --- a/remote/test/puppeteer/test/assets/serviceworkers/fetch/sw.html +++ b/remote/test/puppeteer/test/assets/serviceworkers/fetch/sw.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <link rel="stylesheet" href="./style.css"> <script> window.registrationPromise = navigator.serviceWorker.register('sw.js'); diff --git a/remote/test/puppeteer/test/assets/shadow.html b/remote/test/puppeteer/test/assets/shadow.html index 3796ca768c..cd64eb0faf 100644 --- a/remote/test/puppeteer/test/assets/shadow.html +++ b/remote/test/puppeteer/test/assets/shadow.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> let h1 = null; diff --git a/remote/test/puppeteer/test/assets/tamperable.html b/remote/test/puppeteer/test/assets/tamperable.html index d027e97038..501d92c3ac 100644 --- a/remote/test/puppeteer/test/assets/tamperable.html +++ b/remote/test/puppeteer/test/assets/tamperable.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> window.result = window.injected; </script>
\ No newline at end of file diff --git a/remote/test/puppeteer/test/assets/title.html b/remote/test/puppeteer/test/assets/title.html index 88a86ce412..6e81f4091a 100644 --- a/remote/test/puppeteer/test/assets/title.html +++ b/remote/test/puppeteer/test/assets/title.html @@ -1 +1,2 @@ +<!DOCTYPE html> <title>Woof-Woof</title> diff --git a/remote/test/puppeteer/test/assets/wrappedlink.html b/remote/test/puppeteer/test/assets/wrappedlink.html index 429b6e9156..da2cd0da3d 100644 --- a/remote/test/puppeteer/test/assets/wrappedlink.html +++ b/remote/test/puppeteer/test/assets/wrappedlink.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> :root { font-family: monospace; diff --git a/remote/test/puppeteer/test/fixtures/closeme.js b/remote/test/puppeteer/test/fixtures/closeme.js index dbe798f70d..a534f9acde 100644 --- a/remote/test/puppeteer/test/fixtures/closeme.js +++ b/remote/test/puppeteer/test/fixtures/closeme.js @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ (async () => { const [, , puppeteerRoot, options] = process.argv; const browser = await require(puppeteerRoot).launch(JSON.parse(options)); diff --git a/remote/test/puppeteer/test/fixtures/dumpio.js b/remote/test/puppeteer/test/fixtures/dumpio.js index a16cf4d633..3df71b43b5 100644 --- a/remote/test/puppeteer/test/fixtures/dumpio.js +++ b/remote/test/puppeteer/test/fixtures/dumpio.js @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ (async () => { const [, , puppeteerRoot, options] = process.argv; const browser = await require(puppeteerRoot).launch(JSON.parse(options)); diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer/tsconfig.json b/remote/test/puppeteer/test/installation/assets/puppeteer/tsconfig.json index ce77dbf8d9..fa9c8a13fd 100644 --- a/remote/test/puppeteer/test/installation/assets/puppeteer/tsconfig.json +++ b/remote/test/puppeteer/test/installation/assets/puppeteer/tsconfig.json @@ -2,6 +2,6 @@ "compilerOptions": { "target": "ES2022", "module": "NodeNext", - "moduleResolution": "NodeNext", - }, + "moduleResolution": "NodeNext" + } } diff --git a/remote/test/puppeteer/test/installation/package.json b/remote/test/puppeteer/test/installation/package.json index f5e804d99c..bd21ac4b0a 100644 --- a/remote/test/puppeteer/test/installation/package.json +++ b/remote/test/puppeteer/test/installation/package.json @@ -5,7 +5,7 @@ "private": true, "scripts": { "build": "wireit", - "clean": "../../tools/clean.js", + "clean": "../../tools/clean.mjs", "test": "mocha" }, "wireit": { @@ -45,6 +45,6 @@ ], "dependencies": { "glob": "10.3.10", - "mocha": "10.2.0" + "mocha": "10.3.0" } } diff --git a/remote/test/puppeteer/test/installation/src/puppeteer.spec.ts b/remote/test/puppeteer/test/installation/src/puppeteer.spec.ts index d7b8757284..ac0a96f1d1 100644 --- a/remote/test/puppeteer/test/installation/src/puppeteer.spec.ts +++ b/remote/test/puppeteer/test/installation/src/puppeteer.spec.ts @@ -41,31 +41,6 @@ describe('`puppeteer`', () => { // Skipping this test on Windows as windows runners are much slower. (platform() === 'win32' ? describe.skip : describe)( - '`puppeteer` with PUPPETEER_DOWNLOAD_PATH', - () => { - configureSandbox({ - dependencies: ['@puppeteer/browsers', 'puppeteer-core', 'puppeteer'], - env: cwd => { - return { - PUPPETEER_DOWNLOAD_PATH: join(cwd, '.cache', 'puppeteer'), - }; - }, - }); - - it('evaluates', async function () { - const files = await readdir(join(this.sandbox, '.cache', 'puppeteer')); - assert.equal(files.length, 2); - assert(files.includes('chrome')); - assert(files.includes('chrome-headless-shell')); - - const script = await readAsset('puppeteer', 'basic.js'); - await this.runScript(script, 'mjs'); - }); - } -); - -// Skipping this test on Windows as windows runners are much slower. -(platform() === 'win32' ? describe.skip : describe)( '`puppeteer` clears cache', () => { configureSandbox({ diff --git a/remote/test/puppeteer/test/installation/tsconfig.json b/remote/test/puppeteer/test/installation/tsconfig.json index 146127b470..f749dd8a07 100644 --- a/remote/test/puppeteer/test/installation/tsconfig.json +++ b/remote/test/puppeteer/test/installation/tsconfig.json @@ -4,7 +4,7 @@ "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "build", - "rootDir": "src", + "rootDir": "src" }, - "include": ["src"], + "include": ["src"] } diff --git a/remote/test/puppeteer/test/package.json b/remote/test/puppeteer/test/package.json index 6470297572..df6cc63731 100644 --- a/remote/test/puppeteer/test/package.json +++ b/remote/test/puppeteer/test/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "build": "wireit", - "clean": "../tools/clean.js" + "clean": "../tools/clean.mjs" }, "wireit": { "build": { @@ -24,7 +24,7 @@ } }, "dependencies": { - "diff": "5.1.0", + "diff": "5.2.0", "jpeg-js": "0.4.4", "pixelmatch": "5.3.0", "pngjs": "7.0.0" diff --git a/remote/test/puppeteer/test/src/ariaqueryhandler.spec.ts b/remote/test/puppeteer/test/src/ariaqueryhandler.spec.ts index 434d01426a..0ffb8ae6a5 100644 --- a/remote/test/puppeteer/test/src/ariaqueryhandler.spec.ts +++ b/remote/test/puppeteer/test/src/ariaqueryhandler.spec.ts @@ -370,9 +370,10 @@ describe('AriaQueryHandler', () => { await detachFrame(page, 'frame1'); await waitPromise; expect(waitError).toBeTruthy(); - expect(waitError.message).toContain( - 'waitForFunction failed: frame got detached.' - ); + expect(waitError.message).atLeastOneToContain([ + 'waitForFunction failed: frame got detached.', + 'Browsing context already closed.', + ]); }); it('should survive cross-process navigation', async () => { diff --git a/remote/test/puppeteer/test/src/browser.spec.ts b/remote/test/puppeteer/test/src/browser.spec.ts index 6f21af5d9a..b8e0c8bb07 100644 --- a/remote/test/puppeteer/test/src/browser.spec.ts +++ b/remote/test/puppeteer/test/src/browser.spec.ts @@ -52,7 +52,9 @@ describe('Browser specs', function () { expect(process!.pid).toBeGreaterThan(0); }); it('should not return child_process for remote browser', async () => { - const {browser, puppeteer} = await getTestState(); + const {browser, puppeteer} = await getTestState({ + skipContextCreation: true, + }); const browserWSEndpoint = browser.wsEndpoint(); const remoteBrowser = await puppeteer.connect({ @@ -66,7 +68,9 @@ describe('Browser specs', function () { describe('Browser.isConnected', () => { it('should set the browser connected state', async () => { - const {browser, puppeteer} = await getTestState(); + const {browser, puppeteer} = await getTestState({ + skipContextCreation: true, + }); const browserWSEndpoint = browser.wsEndpoint(); const newBrowser = await puppeteer.connect({ diff --git a/remote/test/puppeteer/test/src/browsercontext.spec.ts b/remote/test/puppeteer/test/src/browsercontext.spec.ts index 9cbbda60a4..27709e90bf 100644 --- a/remote/test/puppeteer/test/src/browsercontext.spec.ts +++ b/remote/test/puppeteer/test/src/browsercontext.spec.ts @@ -18,9 +18,13 @@ describe('BrowserContext', function () { const {browser} = await getTestState({ skipContextCreation: true, }); - expect(browser.browserContexts()).toHaveLength(1); - const defaultContext = browser.browserContexts()[0]!; - expect(defaultContext!.isIncognito()).toBe(false); + + expect(browser.browserContexts().length).toBeGreaterThanOrEqual(1); + const defaultContext = browser.browserContexts().find(context => { + return !context.isIncognito(); + }); + expect(defaultContext).toBeDefined(); + let error!: Error; await defaultContext!.close().catch(error_ => { return (error = error_); @@ -33,13 +37,14 @@ describe('BrowserContext', function () { skipContextCreation: true, }); - expect(browser.browserContexts()).toHaveLength(1); - const context = await browser.createIncognitoBrowserContext(); + const contextCount = browser.browserContexts().length; + expect(contextCount).toBeGreaterThanOrEqual(1); + const context = await browser.createBrowserContext(); expect(context.isIncognito()).toBe(true); - expect(browser.browserContexts()).toHaveLength(2); + expect(browser.browserContexts()).toHaveLength(contextCount + 1); expect(browser.browserContexts().indexOf(context) !== -1).toBe(true); await context.close(); - expect(browser.browserContexts()).toHaveLength(1); + expect(browser.browserContexts()).toHaveLength(contextCount); }); it('should close all belonging targets once closing context', async () => { const {browser} = await getTestState({ @@ -48,7 +53,7 @@ describe('BrowserContext', function () { expect(await browser.pages()).toHaveLength(1); - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); await context.newPage(); expect(await browser.pages()).toHaveLength(2); expect(await context.pages()).toHaveLength(1); @@ -128,7 +133,7 @@ describe('BrowserContext', function () { it('should timeout waiting for a non-existent target', async () => { const {browser, server} = await getTestState(); - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); const error = await context .waitForTarget( target => { @@ -151,8 +156,8 @@ describe('BrowserContext', function () { }); // Create two incognito contexts. - const context1 = await browser.createIncognitoBrowserContext(); - const context2 = await browser.createIncognitoBrowserContext(); + const context1 = await browser.createBrowserContext(); + const context2 = await browser.createBrowserContext(); expect(context1.targets()).toHaveLength(0); expect(context2.targets()).toHaveLength(0); @@ -176,9 +181,9 @@ describe('BrowserContext', function () { }); expect(context1.targets()).toHaveLength(1); - expect(context1.targets()[0]).toBe(page1.target()); + expect(await context1.targets()[0]?.page()).toBe(page1); expect(context2.targets()).toHaveLength(1); - expect(context2.targets()[0]).toBe(page2.target()); + expect(await context2.targets()[0]?.page()).toBe(page2); // Make sure pages don't share localstorage or cookies. expect( @@ -213,16 +218,19 @@ describe('BrowserContext', function () { }); expect(browser.browserContexts()).toHaveLength(1); - const context = await browser.createIncognitoBrowserContext(); - expect(browser.browserContexts()).toHaveLength(2); - const remoteBrowser = await puppeteer.connect({ - browserWSEndpoint: browser.wsEndpoint(), - protocol: browser.protocol, - }); - const contexts = remoteBrowser.browserContexts(); - expect(contexts).toHaveLength(2); - await remoteBrowser.disconnect(); - await context.close(); + const context = await browser.createBrowserContext(); + try { + expect(browser.browserContexts()).toHaveLength(2); + const remoteBrowser = await puppeteer.connect({ + browserWSEndpoint: browser.wsEndpoint(), + protocol: browser.protocol, + }); + const contexts = remoteBrowser.browserContexts(); + expect(contexts).toHaveLength(2); + await remoteBrowser.disconnect(); + } finally { + await context.close(); + } }); it('should provide a context id', async () => { @@ -233,7 +241,7 @@ describe('BrowserContext', function () { expect(browser.browserContexts()).toHaveLength(1); expect(browser.browserContexts()[0]!.id).toBeUndefined(); - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); expect(browser.browserContexts()).toHaveLength(2); expect(browser.browserContexts()[1]!.id).toBeDefined(); await context.close(); @@ -333,7 +341,7 @@ describe('BrowserContext', function () { const {page, server, context, browser} = await getTestState(); await page.goto(server.EMPTY_PAGE); - const otherContext = await browser.createIncognitoBrowserContext(); + const otherContext = await browser.createBrowserContext(); const otherPage = await otherContext.newPage(); await otherPage.goto(server.EMPTY_PAGE); expect(await getPermission(page, 'geolocation')).toBe('prompt'); diff --git a/remote/test/puppeteer/test/src/cdp/CDPSession.spec.ts b/remote/test/puppeteer/test/src/cdp/CDPSession.spec.ts index 2000c0e435..887152f097 100644 --- a/remote/test/puppeteer/test/src/cdp/CDPSession.spec.ts +++ b/remote/test/puppeteer/test/src/cdp/CDPSession.spec.ts @@ -30,7 +30,7 @@ describe('Target.createCDPSession', function () { }); it('should not report created targets for custom CDP sessions', async () => { - const {browser} = await getTestState(); + const {context} = await getTestState(); let called = 0; const handler = async (target: Target) => { called++; @@ -39,9 +39,9 @@ describe('Target.createCDPSession', function () { } await target.createCDPSession(); }; - browser.browserContexts()[0]!.on('targetcreated', handler); - await browser.newPage(); - browser.browserContexts()[0]!.off('targetcreated', handler); + context.on('targetcreated', handler); + await context.newPage(); + context.off('targetcreated', handler); }); it('should send events', async () => { diff --git a/remote/test/puppeteer/test/src/cdp/devtools.spec.ts b/remote/test/puppeteer/test/src/cdp/devtools.spec.ts index c158481af2..c48b4c353b 100644 --- a/remote/test/puppeteer/test/src/cdp/devtools.spec.ts +++ b/remote/test/puppeteer/test/src/cdp/devtools.spec.ts @@ -93,7 +93,7 @@ describe('DevTools', function () { const browser = await launchBrowser( Object.assign({devtools: true}, launchOptions) ); - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); await Promise.all([ context.newPage(), browser.waitForTarget((target: {url: () => string | string[]}) => { @@ -106,7 +106,7 @@ describe('DevTools', function () { const browser = await launchBrowser( Object.assign({devtools: true}, launchOptions) ); - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); const [target] = await Promise.all([ browser.waitForTarget((target: {url: () => string | string[]}) => { return target.url().includes('devtools://'); diff --git a/remote/test/puppeteer/test/src/cdp/pdf.spec.ts b/remote/test/puppeteer/test/src/cdp/pdf.spec.ts new file mode 100644 index 0000000000..06a41de36f --- /dev/null +++ b/remote/test/puppeteer/test/src/cdp/pdf.spec.ts @@ -0,0 +1,55 @@ +/** + * @license + * Copyright 2017 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import {readFile, unlink} from 'fs/promises'; + +import expect from 'expect'; + +import {getTestState, setupTestBrowserHooks} from '../mocha-utils.js'; + +describe('Page.pdf', () => { + setupTestBrowserHooks(); + + it('can print to PDF with accessible', async () => { + const {page, server} = await getTestState(); + + const outputFile = __dirname + '/../../assets/output.pdf'; + const outputFileAccessible = + __dirname + '/../../assets/output-accessible.pdf'; + await page.goto(server.PREFIX + '/pdf.html'); + await page.pdf({path: outputFile, tagged: false}); + await page.pdf({path: outputFileAccessible, tagged: true}); + try { + const [base, tagged] = await Promise.all([ + readFile(outputFile), + readFile(outputFileAccessible), + ]); + expect(tagged.byteLength).toBeGreaterThan(base.byteLength); + } finally { + await Promise.all([unlink(outputFile), unlink(outputFileAccessible)]); + } + }); + + it('can print to PDF with outline', async () => { + const {page, server} = await getTestState(); + + const outputFile = __dirname + '/../../assets/output.pdf'; + const outputFileOutlined = __dirname + '/../../assets/output-outlined.pdf'; + await page.goto(server.PREFIX + '/pdf.html'); + await page.pdf({path: outputFile, tagged: true}); + await page.pdf({path: outputFileOutlined, tagged: true, outline: true}); + try { + const [base, outlined] = await Promise.all([ + readFile(outputFile), + readFile(outputFileOutlined), + ]); + + expect(outlined.byteLength).toBeGreaterThan(base.byteLength); + } finally { + await Promise.all([unlink(outputFile), unlink(outputFileOutlined)]); + } + }); +}); diff --git a/remote/test/puppeteer/test/src/screencast.spec.ts b/remote/test/puppeteer/test/src/cdp/screencast.spec.ts index b645f55da7..2833ff4d67 100644 --- a/remote/test/puppeteer/test/src/screencast.spec.ts +++ b/remote/test/puppeteer/test/src/cdp/screencast.spec.ts @@ -8,8 +8,8 @@ import {statSync} from 'fs'; import expect from 'expect'; -import {getTestState, setupTestBrowserHooks} from './mocha-utils.js'; -import {getUniqueVideoFilePlaceholder} from './utils.js'; +import {getTestState, setupTestBrowserHooks} from '../mocha-utils.js'; +import {getUniqueVideoFilePlaceholder} from '../utils.js'; describe('Screencasts', function () { setupTestBrowserHooks(); diff --git a/remote/test/puppeteer/test/src/cookies.spec.ts b/remote/test/puppeteer/test/src/cookies.spec.ts index f232831b72..1fa4a9407c 100644 --- a/remote/test/puppeteer/test/src/cookies.spec.ts +++ b/remote/test/puppeteer/test/src/cookies.spec.ts @@ -150,9 +150,7 @@ describe('Cookie specs', () => { expires: -1, size: 11, httpOnly: false, - secure: true, session: true, - sourcePort: 443, sourceScheme: 'Secure', }, { @@ -164,13 +162,47 @@ describe('Cookie specs', () => { expires: -1, size: 10, httpOnly: false, - secure: true, session: true, - sourcePort: 443, sourceScheme: 'Secure', }, ]); }); + it('should not get cookies from subdomain', async () => { + const {page} = await getTestState(); + await page.setCookie({ + url: 'https://base_domain.com', + name: 'doggo', + value: 'woofs', + }); + const cookies = await page.cookies('https://sub_domain.base_domain.com'); + expect(cookies).toHaveLength(0); + }); + it('should get cookies from nested path', async () => { + const {page} = await getTestState(); + await page.setCookie({ + url: 'https://foo.com', + path: '/some_path', + name: 'doggo', + value: 'woofs', + }); + const cookies = await page.cookies( + 'https://foo.com/some_path/nested_path' + ); + expect(cookies).toHaveLength(1); + }); + it('should not get cookies from not nested path', async () => { + const {page} = await getTestState(); + await page.setCookie({ + url: 'https://foo.com', + path: '/some_path', + name: 'doggo', + value: 'woofs', + }); + const cookies = await page.cookies( + 'https://foo.com/some_path_looks_like_nested' + ); + expect(cookies).toHaveLength(0); + }); }); describe('Page.setCookie', function () { it('should work', async () => { @@ -190,24 +222,27 @@ describe('Cookie specs', () => { it('should isolate cookies in browser contexts', async () => { const {page, server, browser} = await getTestState(); - const anotherContext = await browser.createIncognitoBrowserContext(); - const anotherPage = await anotherContext.newPage(); + const anotherContext = await browser.createBrowserContext(); + try { + const anotherPage = await anotherContext.newPage(); - await page.goto(server.EMPTY_PAGE); - await anotherPage.goto(server.EMPTY_PAGE); - - await page.setCookie({name: 'page1cookie', value: 'page1value'}); - await anotherPage.setCookie({name: 'page2cookie', value: 'page2value'}); - - const cookies1 = await page.cookies(); - const cookies2 = await anotherPage.cookies(); - expect(cookies1).toHaveLength(1); - expect(cookies2).toHaveLength(1); - expect(cookies1[0]!.name).toBe('page1cookie'); - expect(cookies1[0]!.value).toBe('page1value'); - expect(cookies2[0]!.name).toBe('page2cookie'); - expect(cookies2[0]!.value).toBe('page2value'); - await anotherContext.close(); + await page.goto(server.EMPTY_PAGE); + await anotherPage.goto(server.EMPTY_PAGE); + + await page.setCookie({name: 'page1cookie', value: 'page1value'}); + await anotherPage.setCookie({name: 'page2cookie', value: 'page2value'}); + + const cookies1 = await page.cookies(); + const cookies2 = await anotherPage.cookies(); + expect(cookies1).toHaveLength(1); + expect(cookies2).toHaveLength(1); + expect(cookies1[0]!.name).toBe('page1cookie'); + expect(cookies1[0]!.value).toBe('page1value'); + expect(cookies2[0]!.name).toBe('page2cookie'); + expect(cookies2[0]!.value).toBe('page2value'); + } finally { + await anotherContext.close(); + } }); it('should set multiple cookies', async () => { const {page, server} = await getTestState(); @@ -271,7 +306,6 @@ describe('Cookie specs', () => { httpOnly: false, secure: false, session: true, - sourcePort: 80, sourceScheme: 'NonSecure', }, ] @@ -298,7 +332,6 @@ describe('Cookie specs', () => { httpOnly: false, secure: false, session: true, - sourcePort: 80, sourceScheme: 'NonSecure', }, ]); @@ -401,9 +434,7 @@ describe('Cookie specs', () => { expires: -1, size: 18, httpOnly: false, - secure: true, session: true, - sourcePort: 443, sourceScheme: 'Secure', }, ]); @@ -446,7 +477,6 @@ describe('Cookie specs', () => { httpOnly: false, secure: false, session: true, - sourcePort: 80, sourceScheme: 'NonSecure', }, ]); @@ -465,7 +495,6 @@ describe('Cookie specs', () => { httpOnly: false, secure: false, session: true, - sourcePort: 80, sourceScheme: 'NonSecure', }, ] @@ -515,7 +544,6 @@ describe('Cookie specs', () => { sameSite: 'None', secure: true, session: true, - sourcePort: 443, sourceScheme: 'Secure', }, ] @@ -527,7 +555,7 @@ describe('Cookie specs', () => { }); describe('Page.deleteCookie', function () { - it('should work', async () => { + it('should delete cookie', async () => { const {page, server} = await getTestState(); await page.goto(server.EMPTY_PAGE); @@ -553,5 +581,139 @@ describe('Cookie specs', () => { 'cookie1=1; cookie3=3' ); }); + it('should not delete cookie for different domain', async () => { + const {page, server} = await getTestState(); + const COOKIE_DESTINATION_URL = 'https://example.com'; + const COOKIE_NAME = 'some_cookie_name'; + + await page.goto(server.EMPTY_PAGE); + // Set a cookie for the current page. + await page.setCookie({ + name: COOKIE_NAME, + value: 'local page cookie value', + }); + expect(await page.cookies()).toHaveLength(1); + + // Set a cookie for different domain. + await page.setCookie({ + url: COOKIE_DESTINATION_URL, + name: COOKIE_NAME, + value: 'COOKIE_DESTINATION_URL cookie value', + }); + expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(1); + + await page.deleteCookie({name: COOKIE_NAME}); + + // Verify the cookie is deleted for the current page. + expect(await page.cookies()).toHaveLength(0); + + // Verify the cookie is not deleted for different domain. + await expectCookieEquals(await page.cookies(COOKIE_DESTINATION_URL), [ + { + name: COOKIE_NAME, + value: 'COOKIE_DESTINATION_URL cookie value', + domain: 'example.com', + path: '/', + sameParty: false, + expires: -1, + size: 51, + httpOnly: false, + secure: true, + session: true, + sourceScheme: 'Secure', + }, + ]); + }); + it('should delete cookie for specified URL', async () => { + const {page, server} = await getTestState(); + const COOKIE_DESTINATION_URL = 'https://example.com'; + const COOKIE_NAME = 'some_cookie_name'; + + await page.goto(server.EMPTY_PAGE); + // Set a cookie for the current page. + await page.setCookie({ + name: COOKIE_NAME, + value: 'some_cookie_value', + }); + expect(await page.cookies()).toHaveLength(1); + + // Set a cookie for specified URL. + await page.setCookie({ + url: COOKIE_DESTINATION_URL, + name: COOKIE_NAME, + value: 'another_cookie_value', + }); + expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(1); + + // Delete the cookie for specified URL. + await page.deleteCookie({ + url: COOKIE_DESTINATION_URL, + name: COOKIE_NAME, + }); + + // Verify the cookie is deleted for specified URL. + expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(0); + + // Verify the cookie is not deleted for the current page. + await expectCookieEquals(await page.cookies(), [ + { + name: COOKIE_NAME, + value: 'some_cookie_value', + domain: 'localhost', + path: '/', + sameParty: false, + expires: -1, + size: 33, + httpOnly: false, + secure: false, + session: true, + sourceScheme: 'NonSecure', + }, + ]); + }); + it('should delete cookie for specified URL regardless of the current page', async () => { + // This test verifies the page.deleteCookie method deletes cookies for the custom + // destination URL, even if it was set from another page. Depending on the cookie + // partitioning implementation, this test case does not pass, if source origin is in + // the default cookie partition. + + const {page, server} = await getTestState(); + const COOKIE_DESTINATION_URL = 'https://example.com'; + const COOKIE_NAME = 'some_cookie_name'; + const URL_1 = server.EMPTY_PAGE; + const URL_2 = server.CROSS_PROCESS_PREFIX + '/empty.html'; + + await page.goto(URL_1); + // Set a cookie for the COOKIE_DESTINATION from URL_1. + await page.setCookie({ + url: COOKIE_DESTINATION_URL, + name: COOKIE_NAME, + value: 'Cookie from URL_1', + }); + expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(1); + + await page.goto(URL_2); + // Set a cookie for the COOKIE_DESTINATION from URL_2. + await page.setCookie({ + url: COOKIE_DESTINATION_URL, + name: COOKIE_NAME, + value: 'Cookie from URL_2', + }); + expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(1); + + // Delete the cookie for the COOKIE_DESTINATION from URL_2. + await page.deleteCookie({ + name: COOKIE_NAME, + url: COOKIE_DESTINATION_URL, + }); + + // Expect the cookie for the COOKIE_DESTINATION from URL_2 is deleted. + expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(0); + + // Navigate back to the URL_1. + await page.goto(server.EMPTY_PAGE); + // Expect the cookie for the COOKIE_DESTINATION from URL_1 is deleted. + expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(0); + }); }); }); diff --git a/remote/test/puppeteer/test/src/coverage.spec.ts b/remote/test/puppeteer/test/src/coverage.spec.ts index 6a95db541c..612d634007 100644 --- a/remote/test/puppeteer/test/src/coverage.spec.ts +++ b/remote/test/puppeteer/test/src/coverage.spec.ts @@ -49,12 +49,11 @@ describe('Coverage specs', function () { await page.coverage.startJSCoverage({reportAnonymousScripts: true}); await page.goto(server.PREFIX + '/jscoverage/eval.html'); const coverage = await page.coverage.stopJSCoverage(); - expect( - coverage.find(entry => { - return entry.url.startsWith('debugger://'); - }) - ).not.toBe(null); - expect(coverage).toHaveLength(2); + + const filtered = coverage.filter(entry => { + return !entry.url.startsWith('debugger://'); + }); + expect(filtered).toHaveLength(1); }); it('should ignore pptr internal scripts if reportAnonymousScripts is true', async () => { const {page, server} = await getTestState(); diff --git a/remote/test/puppeteer/test/src/debugInfo.spec.ts b/remote/test/puppeteer/test/src/debugInfo.spec.ts index 079107cab7..4f79231667 100644 --- a/remote/test/puppeteer/test/src/debugInfo.spec.ts +++ b/remote/test/puppeteer/test/src/debugInfo.spec.ts @@ -15,6 +15,18 @@ describe('DebugInfo', function () { it('should work', async () => { const {page, browser} = await getTestState(); + for (let i = 0; i < 5; i++) { + if (!browser.debugInfo.pendingProtocolErrors.length) { + break; + } + await new Promise(resolve => { + return setTimeout(resolve, 200); + }); + } + + // Insure that the previous test are flushed + expect(browser.debugInfo.pendingProtocolErrors).toHaveLength(0); + const promise = page.evaluate(() => { return new Promise(resolve => { // @ts-expect-error another context diff --git a/remote/test/puppeteer/test/src/defaultbrowsercontext.spec.ts b/remote/test/puppeteer/test/src/defaultbrowsercontext.spec.ts index 69a5a069af..662c6826cb 100644 --- a/remote/test/puppeteer/test/src/defaultbrowsercontext.spec.ts +++ b/remote/test/puppeteer/test/src/defaultbrowsercontext.spec.ts @@ -62,7 +62,6 @@ describe('DefaultBrowserContext', function () { httpOnly: false, secure: false, session: true, - sourcePort: 80, sourceScheme: 'NonSecure', }, ]); @@ -96,7 +95,6 @@ describe('DefaultBrowserContext', function () { httpOnly: false, secure: false, session: true, - sourcePort: 80, sourceScheme: 'NonSecure', }, ]); diff --git a/remote/test/puppeteer/test/src/device-request-prompt.spec.ts b/remote/test/puppeteer/test/src/device-request-prompt.spec.ts index e6e2cdd65e..450a8d800c 100644 --- a/remote/test/puppeteer/test/src/device-request-prompt.spec.ts +++ b/remote/test/puppeteer/test/src/device-request-prompt.spec.ts @@ -28,7 +28,7 @@ describe('device request prompt', function () { }); beforeEach(async () => { - state.context = await state.browser.createIncognitoBrowserContext(); + state.context = await state.browser.createBrowserContext(); state.page = await state.context.newPage(); }); diff --git a/remote/test/puppeteer/test/src/elementhandle.spec.ts b/remote/test/puppeteer/test/src/elementhandle.spec.ts index 9aaf914224..e0f1e41878 100644 --- a/remote/test/puppeteer/test/src/elementhandle.spec.ts +++ b/remote/test/puppeteer/test/src/elementhandle.spec.ts @@ -34,18 +34,14 @@ describe('ElementHandle specs', function () { expect(box).toEqual({x: 100, y: 50, width: 50, height: 50}); }); it('should handle nested frames', async () => { - const {page, server, isChrome} = await getTestState(); + const {page, server} = await getTestState(); await page.setViewport({width: 500, height: 500}); await page.goto(server.PREFIX + '/frames/nested-frames.html'); const nestedFrame = page.frames()[1]!.childFrames()[1]!; using elementHandle = (await nestedFrame.$('div'))!; const box = await elementHandle.boundingBox(); - if (isChrome) { - expect(box).toEqual({x: 28, y: 182, width: 264, height: 18}); - } else { - expect(box).toEqual({x: 28, y: 182, width: 254, height: 18}); - } + expect(box).toEqual({x: 28, y: 182, width: 300, height: 18}); }); it('should return null for invisible elements', async () => { const {page} = await getTestState(); @@ -472,10 +468,8 @@ describe('ElementHandle specs', function () { }) ).toStrictEqual('bar1'); }); - }); - describe('Element.waitForXPath', () => { - it('should wait correctly with waitForXPath on an element', async () => { + it('should wait correctly with waitForSelector and xpath on an element', async () => { const {page} = await getTestState(); // Set the page content after the waitFor has been started. await page.setContent( @@ -490,20 +484,18 @@ describe('ElementHandle specs', function () { </div>` ); - using el1 = (await page.waitForSelector( + using elById = (await page.waitForSelector( '#el1' )) as ElementHandle<HTMLDivElement>; - for (const path of ['//div', './/div']) { - using e = (await el1.waitForXPath( - path - )) as ElementHandle<HTMLDivElement>; - expect( - await e.evaluate(el => { - return el.id; - }) - ).toStrictEqual('el2'); - } + using elByXpath = (await elById.waitForSelector( + 'xpath/.//div' + )) as ElementHandle<HTMLDivElement>; + expect( + await elByXpath.evaluate(el => { + return el.id; + }) + ).toStrictEqual('el2'); }); }); diff --git a/remote/test/puppeteer/test/src/evaluation.spec.ts b/remote/test/puppeteer/test/src/evaluation.spec.ts index 3305b59cc2..88cccb82dd 100644 --- a/remote/test/puppeteer/test/src/evaluation.spec.ts +++ b/remote/test/puppeteer/test/src/evaluation.spec.ts @@ -408,9 +408,10 @@ describe('Evaluation specs', function () { return (error = error_); }); expect(error).toBeTruthy(); - expect(error.message).toContain( - 'JSHandles can be evaluated only in the context they were created' - ); + expect(error.message).atLeastOneToContain([ + 'JSHandles can be evaluated only in the context they were created', + "Trying to evaluate JSHandle from different frames. Usually this means you're using a handle from a page on a different page.", + ]); }); it('should simulate a user gesture', async () => { const {page} = await getTestState(); diff --git a/remote/test/puppeteer/test/src/fixtures.spec.ts b/remote/test/puppeteer/test/src/fixtures.spec.ts index ca11e94cac..e7a2e1ac9b 100644 --- a/remote/test/puppeteer/test/src/fixtures.spec.ts +++ b/remote/test/puppeteer/test/src/fixtures.spec.ts @@ -18,7 +18,7 @@ describe('Fixtures', function () { it('dumpio option should work with pipe option', async () => { const {defaultBrowserOptions, puppeteerPath, headless} = await getTestState(); - if (headless !== 'true') { + if (headless !== 'shell') { // This test only works in the old headless mode. return; } @@ -42,7 +42,8 @@ describe('Fixtures', function () { expect(dumpioData).toContain('message from dumpio'); }); it('should dump browser process stderr', async () => { - const {defaultBrowserOptions, puppeteerPath} = await getTestState(); + const {defaultBrowserOptions, isFirefox, puppeteerPath} = + await getTestState(); let dumpioData = ''; const options = Object.assign({}, defaultBrowserOptions, {dumpio: true}); @@ -57,7 +58,11 @@ describe('Fixtures', function () { await new Promise(resolve => { return res.on('close', resolve); }); - expect(dumpioData).toContain('DevTools listening on ws://'); + if (isFirefox && defaultBrowserOptions.protocol === 'webDriverBiDi') { + expect(dumpioData).toContain('WebDriver BiDi listening on ws://'); + } else { + expect(dumpioData).toContain('DevTools listening on ws://'); + } }); it('should close the browser when the node process closes', async () => { const {defaultBrowserOptions, puppeteerPath, puppeteer} = diff --git a/remote/test/puppeteer/test/src/frame.spec.ts b/remote/test/puppeteer/test/src/frame.spec.ts index 3b2456821a..a49fb19482 100644 --- a/remote/test/puppeteer/test/src/frame.spec.ts +++ b/remote/test/puppeteer/test/src/frame.spec.ts @@ -205,6 +205,18 @@ describe('Frame specs', function () { expect(detachedFrames).toHaveLength(4); expect(navigatedFrames).toHaveLength(1); }); + + it('should click elements in a frameset', async () => { + const {page, server} = await getTestState(); + await page.goto(server.PREFIX + '/frames/frameset.html'); + const frame = await page.waitForFrame(frame => { + return frame.url().endsWith('/frames/frame.html'); + }); + using div = await frame.waitForSelector('div'); + expect(div).toBeTruthy(); + await div?.click(); + }); + it('should report frame from-inside shadow DOM', async () => { const {page, server} = await getTestState(); diff --git a/remote/test/puppeteer/test/src/headful.spec.ts b/remote/test/puppeteer/test/src/headful.spec.ts index 1e3248b4ff..67ae9f335e 100644 --- a/remote/test/puppeteer/test/src/headful.spec.ts +++ b/remote/test/puppeteer/test/src/headful.spec.ts @@ -12,18 +12,18 @@ import expect from 'expect'; import type {PuppeteerLaunchOptions} from 'puppeteer-core/internal/node/PuppeteerNode.js'; import {rmSync} from 'puppeteer-core/internal/node/util/fs.js'; -import {getTestState, isHeadless, launch} from './mocha-utils.js'; +import {getTestState, launch} from './mocha-utils.js'; const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); -(!isHeadless ? describe : describe.skip)('headful tests', function () { +describe('headful tests', function () { /* These tests fire up an actual browser so let's * allow a higher timeout */ this.timeout(20_000); - let headfulOptions: PuppeteerLaunchOptions | undefined; - let headlessOptions: PuppeteerLaunchOptions & {headless: boolean}; + let headfulOptions: PuppeteerLaunchOptions & {headless: false}; + let headlessOptions: PuppeteerLaunchOptions & {headless: true}; const browsers: Array<() => Promise<void>> = []; @@ -32,10 +32,10 @@ const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); skipLaunch: true, }); headfulOptions = Object.assign({}, defaultBrowserOptions, { - headless: false, + headless: false as const, }); headlessOptions = Object.assign({}, defaultBrowserOptions, { - headless: true, + headless: true as const, }); }); @@ -64,23 +64,30 @@ const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); const headfulBrowser = await launchBrowser( Object.assign({userDataDir}, headfulOptions) ); - const headfulPage = await headfulBrowser.newPage(); - await headfulPage.goto(server.EMPTY_PAGE); - await headfulPage.evaluate(() => { - return (document.cookie = - 'foo=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'); - }); - await headfulBrowser.close(); + try { + const headfulPage = await headfulBrowser.newPage(); + await headfulPage.goto(server.EMPTY_PAGE); + await headfulPage.evaluate(() => { + return (document.cookie = + 'foo=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'); + }); + } finally { + await headfulBrowser.close(); + } // Read the cookie from headless chrome const headlessBrowser = await launchBrowser( Object.assign({userDataDir}, headlessOptions) ); - const headlessPage = await headlessBrowser.newPage(); - await headlessPage.goto(server.EMPTY_PAGE); - const cookie = await headlessPage.evaluate(() => { - return document.cookie; - }); - await headlessBrowser.close(); + let cookie = ''; + try { + const headlessPage = await headlessBrowser.newPage(); + await headlessPage.goto(server.EMPTY_PAGE); + cookie = await headlessPage.evaluate(() => { + return document.cookie; + }); + } finally { + await headlessBrowser.close(); + } // This might throw. See https://github.com/puppeteer/puppeteer/issues/2778 try { rmSync(userDataDir); diff --git a/remote/test/puppeteer/test/src/ignorehttpserrors.spec.ts b/remote/test/puppeteer/test/src/ignorehttpserrors.spec.ts index 8fb557cb88..d8e5603388 100644 --- a/remote/test/puppeteer/test/src/ignorehttpserrors.spec.ts +++ b/remote/test/puppeteer/test/src/ignorehttpserrors.spec.ts @@ -32,7 +32,7 @@ describe('ignoreHTTPSErrors', function () { }); beforeEach(async () => { - state.context = await state.browser.createIncognitoBrowserContext(); + state.context = await state.browser.createBrowserContext(); state.page = await state.context.newPage(); }); diff --git a/remote/test/puppeteer/test/src/input.spec.ts b/remote/test/puppeteer/test/src/input.spec.ts index 7e4cae6709..47064528d3 100644 --- a/remote/test/puppeteer/test/src/input.spec.ts +++ b/remote/test/puppeteer/test/src/input.spec.ts @@ -17,14 +17,13 @@ const FILE_TO_UPLOAD = path.join(__dirname, '/../assets/file-to-upload.txt'); describe('input tests', function () { setupTestBrowserHooks(); - describe('input', function () { + describe('ElementHandle.uploadFile', function () { it('should upload the file', async () => { const {page, server} = await getTestState(); await page.goto(server.PREFIX + '/input/fileupload.html'); - const filePath = path.relative(process.cwd(), FILE_TO_UPLOAD); using input = (await page.$('input'))!; - await page.evaluate((e: HTMLElement) => { + await input.evaluate(e => { (globalThis as any)._inputEvents = []; e.addEventListener('change', ev => { return (globalThis as any)._inputEvents.push(ev.type); @@ -32,34 +31,63 @@ describe('input tests', function () { e.addEventListener('input', ev => { return (globalThis as any)._inputEvents.push(ev.type); }); - }, input); - await input.uploadFile(filePath); + }); + + const file = path.relative(process.cwd(), FILE_TO_UPLOAD); + await input.uploadFile(file); + expect( - await page.evaluate((e: HTMLInputElement) => { - return e.files![0]!.name; - }, input) + await input.evaluate(e => { + return e.files?.[0]?.name; + }) ).toBe('file-to-upload.txt'); expect( - await page.evaluate((e: HTMLInputElement) => { - return e.files![0]!.type; - }, input) + await input.evaluate(e => { + return e.files?.[0]?.type; + }) ).toBe('text/plain'); expect( await page.evaluate(() => { return (globalThis as any)._inputEvents; }) ).toEqual(['input', 'change']); + }); + + it('should read the file', async () => { + const {page, server} = await getTestState(); + + await page.goto(server.PREFIX + '/input/fileupload.html'); + using input = (await page.$('input'))!; + await input.evaluate(e => { + (globalThis as any)._inputEvents = []; + e.addEventListener('change', ev => { + return (globalThis as any)._inputEvents.push(ev.type); + }); + e.addEventListener('input', ev => { + return (globalThis as any)._inputEvents.push(ev.type); + }); + }); + + const file = path.relative(process.cwd(), FILE_TO_UPLOAD); + await input.uploadFile(file); + expect( - await page.evaluate((e: HTMLInputElement) => { + await input.evaluate(e => { + const file = e.files?.[0]; + if (!file) { + throw new Error('No file found'); + } + const reader = new FileReader(); const promise = new Promise(fulfill => { - return (reader.onload = fulfill); + reader.addEventListener('load', fulfill); }); - reader.readAsText(e.files![0]!); + reader.readAsText(file); + return promise.then(() => { return reader.result; }); - }, input) + }) ).toBe('contents of the file'); }); }); diff --git a/remote/test/puppeteer/test/src/launcher.spec.ts b/remote/test/puppeteer/test/src/launcher.spec.ts index f31b22b1e5..876f8d1624 100644 --- a/remote/test/puppeteer/test/src/launcher.spec.ts +++ b/remote/test/puppeteer/test/src/launcher.spec.ts @@ -16,7 +16,7 @@ import type {Page} from 'puppeteer-core/internal/api/Page.js'; import {rmSync} from 'puppeteer-core/internal/node/util/fs.js'; import sinon from 'sinon'; -import {getTestState, isHeadless, launch} from './mocha-utils.js'; +import {getTestState, launch} from './mocha-utils.js'; import {dumpFrames, waitEvent} from './utils.js'; const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); @@ -48,7 +48,10 @@ describe('Launcher specs', function () { [ 'Navigating frame was detached', 'Protocol error (Page.navigate): Target closed.', - ].includes(error.message) + 'Protocol error (browsingContext.navigate): Target closed', + ].some(message => { + return error.message.startsWith(message); + }) ).toBeTruthy(); } finally { await close(); @@ -99,6 +102,7 @@ describe('Launcher specs', function () { expect(message).atLeastOneToContain([ 'Target closed', 'Page closed!', + 'Browser already closed', ]); expect(message).not.toContain('Timeout'); } @@ -363,9 +367,9 @@ describe('Launcher specs', function () { if (isChrome) { expect(puppeteer.defaultArgs()).toContain('--no-first-run'); - expect(puppeteer.defaultArgs()).toContain('--headless'); + expect(puppeteer.defaultArgs()).toContain('--headless=new'); expect(puppeteer.defaultArgs({headless: false})).not.toContain( - '--headless' + '--headless=new' ); expect(puppeteer.defaultArgs({userDataDir: 'foo'})).toContain( `--user-data-dir=${path.resolve('foo')}` @@ -408,21 +412,18 @@ describe('Launcher specs', function () { expect(puppeteer.product).toBe('firefox'); } }); - (!isHeadless ? it : it.skip)( - 'should work with no default arguments', - async () => { - const {context, close} = await launch({ - ignoreDefaultArgs: true, - }); - try { - const page = await context.newPage(); - expect(await page.evaluate('11 * 11')).toBe(121); - await page.close(); - } finally { - await close(); - } + it('should work with no default arguments', async () => { + const {context, close} = await launch({ + ignoreDefaultArgs: true, + }); + try { + const page = await context.newPage(); + expect(await page.evaluate('11 * 11')).toBe(121); + await page.close(); + } finally { + await close(); } - ); + }); it('should filter out ignored default arguments in Chrome', async () => { const {defaultBrowserOptions, puppeteer} = await getTestState({ skipLaunch: true, @@ -590,31 +591,6 @@ describe('Launcher specs', function () { }); expect(error.message).toContain('either pipe or debugging port'); }); - (!isHeadless ? it : it.skip)( - 'should launch Chrome properly with --no-startup-window and waitForInitialPage=false', - async () => { - const {defaultBrowserOptions} = await getTestState({ - skipLaunch: true, - }); - const options = { - waitForInitialPage: false, - // This is needed to prevent Puppeteer from adding an initial blank page. - // See also https://github.com/puppeteer/puppeteer/blob/ad6b736039436fcc5c0a262e5b575aa041427be3/src/node/Launcher.ts#L200 - ignoreDefaultArgs: true, - ...defaultBrowserOptions, - args: ['--no-startup-window'], - }; - const {browser, close} = await launch(options, { - createContext: false, - }); - try { - const pages = await browser.pages(); - expect(pages).toHaveLength(0); - } finally { - await close(); - } - } - ); }); describe('Puppeteer.launch', function () { diff --git a/remote/test/puppeteer/test/src/mocha-utils.ts b/remote/test/puppeteer/test/src/mocha-utils.ts index 3fff9c9930..333204d83b 100644 --- a/remote/test/puppeteer/test/src/mocha-utils.ts +++ b/remote/test/puppeteer/test/src/mocha-utils.ts @@ -8,13 +8,13 @@ import fs from 'fs'; import path from 'path'; import {TestServer} from '@pptr/testserver'; -import type {Protocol} from 'devtools-protocol'; import expect from 'expect'; import type * as MochaBase from 'mocha'; import puppeteer from 'puppeteer/lib/cjs/puppeteer/puppeteer.js'; import type {Browser} from 'puppeteer-core/internal/api/Browser.js'; import type {BrowserContext} from 'puppeteer-core/internal/api/BrowserContext.js'; import type {Page} from 'puppeteer-core/internal/api/Page.js'; +import type {Cookie} from 'puppeteer-core/internal/common/Cookie.js'; import type { PuppeteerLaunchOptions, PuppeteerNode, @@ -68,8 +68,8 @@ const product = const headless = (process.env['HEADLESS'] || 'true').trim().toLowerCase() as | 'true' | 'false' - | 'new'; -export const isHeadless = headless === 'true' || headless === 'new'; + | 'shell'; +export const isHeadless = headless === 'true' || headless === 'shell'; const isFirefox = product === 'firefox'; const isChrome = product === 'chrome'; const protocol = (process.env['PUPPETEER_PROTOCOL'] || 'cdp') as @@ -93,7 +93,7 @@ const defaultBrowserOptions = Object.assign( { handleSIGINT: true, executablePath: process.env['BINARY'], - headless: headless === 'new' ? ('new' as const) : isHeadless, + headless: headless === 'shell' ? ('shell' as const) : isHeadless, dumpio: !!process.env['DUMPIO'], protocol, }, @@ -115,7 +115,7 @@ if (defaultBrowserOptions.executablePath) { const processVariables: { product: string; - headless: 'true' | 'false' | 'new'; + headless: 'true' | 'false' | 'shell'; isHeadless: boolean; isFirefox: boolean; isChrome: boolean; @@ -216,7 +216,7 @@ export const getTestState = async ( } if (!skipContextCreation) { - state.context = await state.browser!.createIncognitoBrowserContext(); + state.context = await state.browser!.createBrowserContext(); state.page = await state.context.newPage(); } return state as PuppeteerTestState; @@ -245,7 +245,7 @@ export interface PuppeteerTestState { isFirefox: boolean; isChrome: boolean; isHeadless: boolean; - headless: 'true' | 'false' | 'new'; + headless: 'true' | 'false' | 'shell'; puppeteerPath: string; } const state: Partial<PuppeteerTestState> = {}; @@ -263,7 +263,7 @@ if ( } -> mode: ${ processVariables.isHeadless - ? processVariables.headless === 'new' + ? processVariables.headless === 'true' ? '--headless=new' : '--headless' : 'headful' @@ -372,23 +372,27 @@ expect.extend({ }); export const expectCookieEquals = async ( - cookies: Protocol.Network.Cookie[], - expectedCookies: Array<Partial<Protocol.Network.Cookie>> + cookies: Cookie[], + expectedCookies: Array<Partial<Cookie>> ): Promise<void> => { if (!processVariables.isChrome) { // Only keep standard properties when testing on a browser other than Chrome. expectedCookies = expectedCookies.map(cookie => { - return { - domain: cookie.domain, - expires: cookie.expires, - httpOnly: cookie.httpOnly, - name: cookie.name, - path: cookie.path, - secure: cookie.secure, - session: cookie.session, - size: cookie.size, - value: cookie.value, - }; + return Object.fromEntries( + Object.entries(cookie).filter(([key]) => { + return [ + 'domain', + 'expires', + 'httpOnly', + 'name', + 'path', + 'secure', + 'session', + 'size', + 'value', + ].includes(key); + }) + ); }); } @@ -479,7 +483,7 @@ export const launch = async ( let context: BrowserContext; let page: Page; if (createContext) { - context = await browser.createIncognitoBrowserContext(); + context = await browser.createBrowserContext(); cleanupStorage.push(() => { return context.close(); }); diff --git a/remote/test/puppeteer/test/src/navigation.spec.ts b/remote/test/puppeteer/test/src/navigation.spec.ts index 1f3a51f58a..dd59c98349 100644 --- a/remote/test/puppeteer/test/src/navigation.spec.ts +++ b/remote/test/puppeteer/test/src/navigation.spec.ts @@ -154,10 +154,10 @@ describe('navigation', function () { }); const EXPECTED_SSL_CERT_MESSAGE_REGEX = - /net::ERR_CERT_INVALID|net::ERR_CERT_AUTHORITY_INVALID/; + /net::ERR_CERT_INVALID|net::ERR_CERT_AUTHORITY_INVALID|MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT|SSL_ERROR_UNKNOWN/; it('should fail when navigating to bad SSL', async () => { - const {page, httpsServer, isChrome} = await getTestState(); + const {page, httpsServer} = await getTestState(); // Make sure that network events do not emit 'undefined'. // @see https://crbug.com/750469 @@ -176,18 +176,14 @@ describe('navigation', function () { await page.goto(httpsServer.EMPTY_PAGE).catch(error_ => { return (error = error_); }); - if (isChrome) { - expect(error.message).toMatch(EXPECTED_SSL_CERT_MESSAGE_REGEX); - } else { - expect(error.message).toContain('SSL_ERROR_UNKNOWN'); - } + expect(error.message).toMatch(EXPECTED_SSL_CERT_MESSAGE_REGEX); expect(requests).toHaveLength(2); expect(requests[0]).toBe('request'); expect(requests[1]).toBe('requestfailed'); }); it('should fail when navigating to bad SSL after redirects', async () => { - const {page, server, httpsServer, isChrome} = await getTestState(); + const {page, server, httpsServer} = await getTestState(); server.setRedirect('/redirect/1.html', '/redirect/2.html'); server.setRedirect('/redirect/2.html', '/empty.html'); @@ -195,17 +191,10 @@ describe('navigation', function () { await page.goto(httpsServer.PREFIX + '/redirect/1.html').catch(error_ => { return (error = error_); }); - if (isChrome) { - expect(error.message).toMatch(EXPECTED_SSL_CERT_MESSAGE_REGEX); - } else { - expect(error.message).atLeastOneToContain([ - 'MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT', // Firefox WebDriver BiDi. - 'SSL_ERROR_UNKNOWN ', // Others. - ]); - } + expect(error.message).toMatch(EXPECTED_SSL_CERT_MESSAGE_REGEX); }); it('should fail when main resources failed to load', async () => { - const {page, isChrome} = await getTestState(); + const {page} = await getTestState(); let error!: Error; await page @@ -213,11 +202,9 @@ describe('navigation', function () { .catch(error_ => { return (error = error_); }); - if (isChrome) { - expect(error.message).toContain('net::ERR_CONNECTION_REFUSED'); - } else { - expect(error.message).toContain('NS_ERROR_CONNECTION_REFUSED'); - } + expect(error.message).toMatch( + /net::ERR_CONNECTION_REFUSED|NS_ERROR_CONNECTION_REFUSED/ + ); }); it('should fail when exceeding maximum navigation timeout', async () => { const {page, server} = await getTestState(); diff --git a/remote/test/puppeteer/test/src/oopif.spec.ts b/remote/test/puppeteer/test/src/oopif.spec.ts index c024b76aba..0213e14d5d 100644 --- a/remote/test/puppeteer/test/src/oopif.spec.ts +++ b/remote/test/puppeteer/test/src/oopif.spec.ts @@ -5,10 +5,9 @@ */ import expect from 'expect'; -import type {BrowserContext} from 'puppeteer-core/internal/api/BrowserContext.js'; import type {CDPSession} from 'puppeteer-core/internal/api/CDPSession.js'; import {CDPSessionEvent} from 'puppeteer-core/internal/api/CDPSession.js'; -import type {CdpTarget} from 'puppeteer-core/internal/cdp/Target.js'; +import type {Page} from 'puppeteer-core/internal/api/Page.js'; import {getTestState, launch} from './mocha-utils.js'; import {attachFrame, detachFrame, navigateFrame} from './utils.js'; @@ -33,7 +32,7 @@ describe('OOPIF', function () { }); beforeEach(async () => { - state.context = await state.browser.createIncognitoBrowserContext(); + state.context = await state.browser.createBrowserContext(); state.page = await state.context.newPage(); }); @@ -222,7 +221,7 @@ describe('OOPIF', function () { it('should provide access to elements', async () => { const {server, isHeadless, headless, page} = state; - if (!isHeadless || headless === 'new') { + if (!isHeadless || headless === 'true') { // TODO: this test is partially blocked on crbug.com/1334119. Enable test once // the upstream is fixed. // TLDR: when we dispatch events to the frame the compositor might @@ -266,24 +265,24 @@ describe('OOPIF', function () { await frame.waitForSelector('#clicked'); }); it('should report oopif frames', async () => { - const {server, page, context} = state; + const {server, page} = state; const frame = page.waitForFrame(frame => { return frame.url().endsWith('/oopif.html'); }); await page.goto(server.PREFIX + '/dynamic-oopif.html'); await frame; - expect(oopifs(context)).toHaveLength(1); + expect(await iframes(page)).toHaveLength(1); expect(page.frames()).toHaveLength(2); }); it('should wait for inner OOPIFs', async () => { - const {server, page, context} = state; + const {server, page} = state; await page.goto(`http://mainframe:${server.PORT}/main-frame.html`); const frame2 = await page.waitForFrame(frame => { return frame.url().endsWith('inner-frame2.html'); }); - expect(oopifs(context)).toHaveLength(2); + expect(await iframes(page)).toHaveLength(2); expect( page.frames().filter(frame => { return frame.isOOPFrame(); @@ -297,7 +296,7 @@ describe('OOPIF', function () { }); it('should load oopif iframes with subresources and request interception', async () => { - const {server, page, context} = state; + const {server, page} = state; const framePromise = page.waitForFrame(frame => { return frame.url().endsWith('/oopif.html'); @@ -312,7 +311,7 @@ describe('OOPIF', function () { await page.goto(server.PREFIX + '/dynamic-oopif.html'); const frame = await framePromise; const request = await requestPromise; - expect(oopifs(context)).toHaveLength(1); + expect(await iframes(page)).toHaveLength(1); expect(request.frame()).toBe(frame); }); @@ -394,14 +393,14 @@ describe('OOPIF', function () { }); it('should detect existing OOPIFs when Puppeteer connects to an existing page', async () => { - const {server, puppeteer, page, context} = state; + const {server, puppeteer, page} = state; const frame = page.waitForFrame(frame => { return frame.url().endsWith('/oopif.html'); }); await page.goto(server.PREFIX + '/dynamic-oopif.html'); await frame; - expect(oopifs(context)).toHaveLength(1); + expect(await iframes(page)).toHaveLength(1); expect(page.frames()).toHaveLength(2); const browserURL = 'http://127.0.0.1:21222'; @@ -472,7 +471,7 @@ describe('OOPIF', function () { const {server, page} = state; // Setup our session listeners to observe OOPIF activity. - const session = await page.target().createCDPSession(); + const session = await page.createCDPSession(); const networkEvents: string[] = []; const otherSessions: CDPSession[] = []; await session.send('Target.setAutoAttach', { @@ -520,8 +519,13 @@ describe('OOPIF', function () { }); }); -function oopifs(context: BrowserContext) { - return context.targets().filter(target => { - return (target as CdpTarget)._getTargetInfo().type === 'iframe'; +async function iframes(page: Page) { + const iframes = await Promise.all( + page.frames().map(async frame => { + return await frame.frameElement(); + }) + ); + return iframes.filter(frame => { + return frame !== null; }); } diff --git a/remote/test/puppeteer/test/src/page.spec.ts b/remote/test/puppeteer/test/src/page.spec.ts index 79fc69ebbc..d83920d3ff 100644 --- a/remote/test/puppeteer/test/src/page.spec.ts +++ b/remote/test/puppeteer/test/src/page.spec.ts @@ -15,6 +15,7 @@ import type {HTTPRequest} from 'puppeteer-core/internal/api/HTTPRequest.js'; import type {Metrics, Page} from 'puppeteer-core/internal/api/Page.js'; import type {CdpPage} from 'puppeteer-core/internal/cdp/Page.js'; import type {ConsoleMessage} from 'puppeteer-core/internal/common/ConsoleMessage.js'; +import {Deferred} from 'puppeteer-core/internal/util/Deferred.js'; import sinon from 'sinon'; import {getTestState, setupTestBrowserHooks} from './mocha-utils.js'; @@ -42,9 +43,9 @@ describe('Page', function () { expect(error.message).toContain('Protocol error'); }); it('should not be visible in browser.pages', async () => { - const {browser} = await getTestState(); + const {browser, context} = await getTestState(); - const newPage = await browser.newPage(); + const newPage = await context.newPage(); expect(await browser.pages()).toContain(newPage); await newPage.close(); expect(await browser.pages()).not.toContain(newPage); @@ -102,7 +103,11 @@ describe('Page', function () { ]); for (let i = 0; i < 2; i++) { const message = results[i].message; - expect(message).atLeastOneToContain(['Target closed', 'Page closed!']); + expect(message).atLeastOneToContain([ + 'Target closed', + 'Page closed!', + 'Frame detached', + ]); expect(message).not.toContain('Timeout'); } }); @@ -445,7 +450,7 @@ describe('Page', function () { messages.map(msg => { return msg.type(); }) - ).toEqual(['trace', 'dir', 'warning', 'error', 'log']); + ).toEqual(['trace', 'dir', 'warn', 'error', 'log']); expect( messages.map(msg => { return msg.text(); @@ -492,6 +497,21 @@ describe('Page', function () { 'JSHandle@window', ]); }); + it('should return remote objects', async () => { + const {page} = await getTestState(); + + const logPromise = waitEvent<ConsoleMessage>(page, 'console'); + await page.evaluate(() => { + (globalThis as any).test = 1; + console.log(1, 2, 3, globalThis); + }); + const log = await logPromise; + expect(log.text()).toBe('1 2 3 JSHandle@object'); + expect(log.args()).toHaveLength(4); + expect(await (await log.args()[3]!.getProperty('test')).jsonValue()).toBe( + 1 + ); + }); it('should trigger correct Log', async () => { const {page, server, isChrome} = await getTestState(); @@ -583,14 +603,10 @@ describe('Page', function () { // 3. After that, remove the iframe. frame.remove(); }); - const popupTarget = page - .browserContext() - .targets() - .find(target => { - return target !== page.target(); - })!; - // 4. Connect to the popup and make sure it doesn't throw. - await popupTarget.page(); + // 4. The target will always be the last one. + const popupTarget = page.browserContext().targets().at(-1)!; + // 5. Connect to the popup and make sure it doesn't throw and is not the same page. + expect(await popupTarget.page()).not.toBe(page); }); }); @@ -1015,15 +1031,15 @@ describe('Page', function () { it('should be callable from-inside evaluateOnNewDocument', async () => { const {page} = await getTestState(); - let called = false; + const called = new Deferred<void>(); await page.exposeFunction('woof', function () { - called = true; + called.resolve(); }); await page.evaluateOnNewDocument(() => { return (globalThis as any).woof(); }); await page.reload(); - expect(called).toBe(true); + await called.valueOrThrow(); }); it('should survive navigation', async () => { const {page, server} = await getTestState(); @@ -1217,7 +1233,7 @@ describe('Page', function () { page.goto(server.PREFIX + '/error.html'), ]); expect(error.message).toContain('Fancy'); - expect(error.stack?.split('\n')[1]).toContain('error.html:13'); + expect(error.stack?.split('\n').at(-1)).toContain('error.html:3:1'); }); }); @@ -1940,33 +1956,20 @@ describe('Page', function () { } }); - it('can print to PDF with accessible', async () => { - const {page, server} = await getTestState(); - - const outputFile = __dirname + '/../assets/output.pdf'; - const outputFileAccessible = - __dirname + '/../assets/output-accessible.pdf'; - await page.goto(server.PREFIX + '/pdf.html'); - await page.pdf({path: outputFile}); - await page.pdf({path: outputFileAccessible, tagged: true}); - try { - expect( - fs.readFileSync(outputFileAccessible).byteLength - ).toBeGreaterThan(fs.readFileSync(outputFile).byteLength); - } finally { - fs.unlinkSync(outputFileAccessible); - fs.unlinkSync(outputFile); - } - }); - it('can print to PDF and stream the result', async () => { const {page} = await getTestState(); const stream = await page.createPDFStream(); let size = 0; - for await (const chunk of stream) { - size += chunk.length; + const reader = stream.getReader(); + while (true) { + const {done, value} = await reader.read(); + if (done) { + break; + } + size += value.length; } + expect(size).toBeGreaterThan(0); }); @@ -2252,9 +2255,9 @@ describe('Page', function () { describe('Page.bringToFront', function () { it('should work', async () => { - const {browser} = await getTestState(); - const page1 = await browser.newPage(); - const page2 = await browser.newPage(); + const {context} = await getTestState(); + const page1 = await context.newPage(); + const page2 = await context.newPage(); await page1.bringToFront(); expect( diff --git a/remote/test/puppeteer/test/src/proxy.spec.ts b/remote/test/puppeteer/test/src/proxy.spec.ts index 07b73cdd0d..1b79cd6665 100644 --- a/remote/test/puppeteer/test/src/proxy.spec.ts +++ b/remote/test/puppeteer/test/src/proxy.spec.ts @@ -150,7 +150,7 @@ describe('request proxy', () => { args: [...defaultArgs, `--proxy-server=${proxyServerUrl}`], }); try { - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); const page = await context.newPage(); const response = (await page.goto(emptyPageUrl))!; @@ -174,7 +174,7 @@ describe('request proxy', () => { ], }); try { - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); const page = await context.newPage(); const response = (await page.goto(emptyPageUrl))!; @@ -197,7 +197,7 @@ describe('request proxy', () => { args: defaultArgs, }); try { - const context = await browser.createIncognitoBrowserContext({ + const context = await browser.createBrowserContext({ proxyServer: proxyServerUrl, }); const page = await context.newPage(); @@ -219,7 +219,7 @@ describe('request proxy', () => { args: defaultArgs, }); try { - const context = await browser.createIncognitoBrowserContext({ + const context = await browser.createBrowserContext({ proxyServer: proxyServerUrl, proxyBypassList: [new URL(emptyPageUrl).host], }); diff --git a/remote/test/puppeteer/test/src/queryselector.spec.ts b/remote/test/puppeteer/test/src/queryselector.spec.ts index 7fd27f914f..c8df118e5f 100644 --- a/remote/test/puppeteer/test/src/queryselector.spec.ts +++ b/remote/test/puppeteer/test/src/queryselector.spec.ts @@ -174,29 +174,29 @@ describe('querySelector', function () { const elements = await page.$$('div'); expect(elements).toHaveLength(0); }); - }); - describe('Page.$x', function () { - it('should query existing element', async () => { - const {page} = await getTestState(); + describe('xpath', function () { + it('should query existing element', async () => { + const {page} = await getTestState(); - await page.setContent('<section>test</section>'); - const elements = await page.$x('/html/body/section'); - expect(elements[0]).toBeTruthy(); - expect(elements).toHaveLength(1); - }); - it('should return empty array for non-existing element', async () => { - const {page} = await getTestState(); + await page.setContent('<section>test</section>'); + const elements = await page.$$('xpath/html/body/section'); + expect(elements[0]).toBeTruthy(); + expect(elements).toHaveLength(1); + }); + it('should return empty array for non-existing element', async () => { + const {page} = await getTestState(); - const element = await page.$x('/html/body/non-existing-element'); - expect(element).toEqual([]); - }); - it('should return multiple elements', async () => { - const {page} = await getTestState(); + const element = await page.$$('xpath/html/body/non-existing-element'); + expect(element).toEqual([]); + }); + it('should return multiple elements', async () => { + const {page} = await getTestState(); - await page.setContent('<div></div><div></div>'); - const elements = await page.$x('/html/body/div'); - expect(elements).toHaveLength(2); + await page.setContent('<div></div><div></div>'); + const elements = await page.$$('xpath/html/body/div'); + expect(elements).toHaveLength(2); + }); }); }); @@ -347,37 +347,40 @@ describe('querySelector', function () { const elements = await html.$$('div'); expect(elements).toHaveLength(0); }); - }); - describe('ElementHandle.$x', function () { - it('should query existing element', async () => { - const {page, server} = await getTestState(); - - await page.goto(server.PREFIX + '/playground.html'); - await page.setContent( - '<html><body><div class="second"><div class="inner">A</div></div></body></html>' - ); - using html = (await page.$('html'))!; - const second = await html.$x(`./body/div[contains(@class, 'second')]`); - const inner = await second[0]!.$x(`./div[contains(@class, 'inner')]`); - const content = await page.evaluate(e => { - return e.textContent; - }, inner[0]!); - expect(content).toBe('A'); - }); + describe('xpath', function () { + it('should query existing element', async () => { + const {page, server} = await getTestState(); + + await page.goto(server.PREFIX + '/playground.html'); + await page.setContent( + '<html><body><div class="second"><div class="inner">A</div></div></body></html>' + ); + using html = (await page.$('html'))!; + const second = await html.$$( + `xpath/./body/div[contains(@class, 'second')]` + ); + const inner = await second[0]!.$$( + `xpath/./div[contains(@class, 'inner')]` + ); + const content = await page.evaluate(e => { + return e.textContent; + }, inner[0]!); + expect(content).toBe('A'); + }); - it('should return null for non-existing element', async () => { - const {page} = await getTestState(); + it('should return null for non-existing element', async () => { + const {page} = await getTestState(); - await page.setContent( - '<html><body><div class="second"><div class="inner">B</div></div></body></html>' - ); - using html = (await page.$('html'))!; - const second = await html.$x(`/div[contains(@class, 'third')]`); - expect(second).toEqual([]); + await page.setContent( + '<html><body><div class="second"><div class="inner">B</div></div></body></html>' + ); + using html = (await page.$('html'))!; + const second = await html.$$(`xpath/div[contains(@class, 'third')]`); + expect(second).toEqual([]); + }); }); }); - // This is the same tests for `$$eval` and `$$` as above, but with a queryAll // handler that returns an array instead of a list of nodes. describe('QueryAll', function () { diff --git a/remote/test/puppeteer/test/src/requestinterception.spec.ts b/remote/test/puppeteer/test/src/requestinterception.spec.ts index 45827bb3cf..4b88d30a3b 100644 --- a/remote/test/puppeteer/test/src/requestinterception.spec.ts +++ b/remote/test/puppeteer/test/src/requestinterception.spec.ts @@ -118,7 +118,7 @@ describe('request interception', function () { await page.goto(server.EMPTY_PAGE); await page.setRequestInterception(true); - const cdp = await page.target().createCDPSession(); + const cdp = await page.createCDPSession(); await cdp.send('DOM.enable'); const urls: string[] = []; page.on('request', request => { diff --git a/remote/test/puppeteer/test/src/screenshot.spec.ts b/remote/test/puppeteer/test/src/screenshot.spec.ts index ad53b60e95..9176d0c920 100644 --- a/remote/test/puppeteer/test/src/screenshot.spec.ts +++ b/remote/test/puppeteer/test/src/screenshot.spec.ts @@ -8,12 +8,7 @@ import assert from 'assert'; import expect from 'expect'; -import { - getTestState, - isHeadless, - launch, - setupTestBrowserHooks, -} from './mocha-utils.js'; +import {getTestState, launch, setupTestBrowserHooks} from './mocha-utils.js'; describe('Screenshots', function () { setupTestBrowserHooks(); @@ -366,7 +361,7 @@ describe('Screenshots', function () { it('should run in parallel in multiple pages', async () => { const {browser, server} = await getTestState(); - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); const N = 2; const pages = await Promise.all( @@ -436,18 +431,15 @@ describe('Screenshots', function () { }); expect(screenshot).toBeGolden('white.jpg'); }); - (!isHeadless ? it : it.skip)( - 'should work in "fromSurface: false" mode', - async () => { - const {page, server} = await getTestState(); + it('should work in "fromSurface: false" mode', async () => { + const {page, server} = await getTestState(); - await page.setViewport({width: 500, height: 500}); - await page.goto(server.PREFIX + '/grid.html'); - const screenshot = await page.screenshot({ - fromSurface: false, - }); - expect(screenshot).toBeDefined(); // toBeGolden('screenshot-fromsurface-false.png'); - } - ); + await page.setViewport({width: 500, height: 500}); + await page.goto(server.PREFIX + '/grid.html'); + const screenshot = await page.screenshot({ + fromSurface: false, + }); + expect(screenshot).toBeDefined(); + }); }); }); diff --git a/remote/test/puppeteer/test/src/target.spec.ts b/remote/test/puppeteer/test/src/target.spec.ts index 28d17a4030..6c1b9cb95e 100644 --- a/remote/test/puppeteer/test/src/target.spec.ts +++ b/remote/test/puppeteer/test/src/target.spec.ts @@ -179,6 +179,29 @@ describe('Target', function () { }) ).toBe('[object ServiceWorkerGlobalScope]'); }); + + it('should close a service worker', async () => { + const {page, server, context} = await getTestState(); + + await page.goto(server.PREFIX + '/serviceworkers/empty/sw.html'); + + const target = await context.waitForTarget( + target => { + return target.type() === 'service_worker'; + }, + {timeout: 3000} + ); + const worker = (await target.worker())!; + + const onceDestroyed = new Promise(resolve => { + context.once('targetdestroyed', event => { + resolve(event); + }); + }); + await worker.close(); + expect(await onceDestroyed).toBe(target); + }); + it('should create a worker from a shared worker', async () => { const {page, server, context} = await getTestState(); @@ -199,6 +222,31 @@ describe('Target', function () { }) ).toBe('[object SharedWorkerGlobalScope]'); }); + + it('should close a shared worker', async () => { + const {page, server, context} = await getTestState(); + + await page.goto(server.EMPTY_PAGE); + await page.evaluate(() => { + new SharedWorker('data:text/javascript,console.log("hi2")'); + }); + const target = await context.waitForTarget( + target => { + return target.type() === 'shared_worker'; + }, + {timeout: 3000} + ); + const worker = (await target.worker())!; + + const onceDestroyed = new Promise(resolve => { + context.once('targetdestroyed', event => { + resolve(event); + }); + }); + await worker.close(); + expect(await onceDestroyed).toBe(target); + }); + it('should report when a target url changes', async () => { const {page, server, context} = await getTestState(); @@ -285,7 +333,7 @@ describe('Target', function () { describe('Browser.waitForTarget', () => { it('should wait for a target', async () => { - const {browser, server} = await getTestState(); + const {browser, server, context} = await getTestState(); let resolved = false; const targetPromise = browser.waitForTarget( @@ -306,7 +354,7 @@ describe('Target', function () { throw error; } }); - const page = await browser.newPage(); + const page = await context.newPage(); expect(resolved).toBe(false); await page.goto(server.EMPTY_PAGE); try { diff --git a/remote/test/puppeteer/test/src/touchscreen.spec.ts b/remote/test/puppeteer/test/src/touchscreen.spec.ts index 28a18ec449..94d8e6fecb 100644 --- a/remote/test/puppeteer/test/src/touchscreen.spec.ts +++ b/remote/test/puppeteer/test/src/touchscreen.spec.ts @@ -15,65 +15,235 @@ describe('Touchscreen', () => { describe('Touchscreen.prototype.tap', () => { it('should work', async () => { - const {page, server, isHeadless} = await getTestState(); + const {page, server} = await getTestState(); await page.goto(server.PREFIX + '/input/touchscreen.html'); await page.tap('button'); expect( - ( - await page.evaluate(() => { - return allEvents; - }) - ).filter(({type}) => { - return type !== 'pointermove' || isHeadless; + await page.evaluate(() => { + return allEvents; }) ).toMatchObject([ - {height: 1, type: 'pointerdown', width: 1, x: 5, y: 5}, - {touches: [[5, 5, 0.5, 0.5]], type: 'touchstart'}, - {height: 1, type: 'pointerup', width: 1, x: 5, y: 5}, - {touches: [[5, 5, 0.5, 0.5]], type: 'touchend'}, - {height: 1, type: 'click', width: 1, x: 5, y: 5}, + { + type: 'pointerdown', + x: 5, + y: 5, + width: 1, + height: 1, + altitudeAngle: Math.PI / 2, + azimuthAngle: 0, + pressure: 0.5, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchstart', + changedTouches: [ + {clientX: 5, clientY: 5, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [ + {clientX: 5, clientY: 5, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + }, + { + type: 'pointerup', + x: 5, + y: 5, + width: 1, + height: 1, + altitudeAngle: Math.PI / 2, + azimuthAngle: 0, + pressure: 0, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchend', + changedTouches: [ + {clientX: 5, clientY: 5, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [], + }, + { + type: 'click', + x: 5, + y: 5, + width: 1, + height: 1, + altitudeAngle: Math.PI / 2, + azimuthAngle: 0, + pressure: 0, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, ]); }); }); describe('Touchscreen.prototype.touchMove', () => { it('should work', async () => { - const {page, server, isHeadless} = await getTestState(); + const {page, server} = await getTestState(); await page.goto(server.PREFIX + '/input/touchscreen.html'); + // Note that touchmoves are sometimes not triggered if consecutive + // touchmoves are less than 15 pixels. + // + // See https://github.com/puppeteer/puppeteer/issues/10836 await page.touchscreen.touchStart(0, 0); - await page.touchscreen.touchMove(10, 10); - await page.touchscreen.touchMove(15.5, 15); - await page.touchscreen.touchMove(20, 20.4); - await page.touchscreen.touchMove(40, 30); + await page.touchscreen.touchMove(15, 15); + await page.touchscreen.touchMove(30.5, 30); + await page.touchscreen.touchMove(50, 45.4); + await page.touchscreen.touchMove(80, 50); await page.touchscreen.touchEnd(); + expect( - ( - await page.evaluate(() => { - return allEvents; - }) - ).filter(({type}) => { - return type !== 'pointermove' || isHeadless; - }) - ).toMatchObject( - [ - {type: 'pointerdown', x: 0, y: 0, width: 1, height: 1}, - {type: 'touchstart', touches: [[0, 0, 0.5, 0.5]]}, - {type: 'pointermove', x: 10, y: 10, width: 1, height: 1}, - {type: 'touchmove', touches: [[10, 10, 0.5, 0.5]]}, - {type: 'pointermove', x: 16, y: 15, width: 1, height: 1}, - {type: 'touchmove', touches: [[16, 15, 0.5, 0.5]]}, - {type: 'pointermove', x: 20, y: 20, width: 1, height: 1}, - {type: 'touchmove', touches: [[20, 20, 0.5, 0.5]]}, - {type: 'pointermove', x: 40, y: 30, width: 1, height: 1}, - {type: 'touchmove', touches: [[40, 30, 0.5, 0.5]]}, - {type: 'pointerup', x: 40, y: 30, width: 1, height: 1}, - {type: 'touchend', touches: [[40, 30, 0.5, 0.5]]}, - ].filter(({type}) => { - return type !== 'pointermove' || isHeadless; + await page.evaluate(() => { + return allEvents; }) - ); + ).toMatchObject([ + { + type: 'pointerdown', + x: 0, + y: 0, + width: 1, + height: 1, + altitudeAngle: 1.5707963267948966, + azimuthAngle: 0, + pressure: 0.5, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchstart', + changedTouches: [ + {clientX: 0, clientY: 0, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [ + {clientX: 0, clientY: 0, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + }, + { + type: 'pointermove', + x: 15, + y: 15, + width: 1, + height: 1, + altitudeAngle: 1.5707963267948966, + azimuthAngle: 0, + pressure: 0.5, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchmove', + changedTouches: [ + {clientX: 15, clientY: 15, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [ + {clientX: 15, clientY: 15, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + }, + { + type: 'pointermove', + x: 31, + y: 30, + width: 1, + height: 1, + altitudeAngle: 1.5707963267948966, + azimuthAngle: 0, + pressure: 0.5, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchmove', + changedTouches: [ + {clientX: 31, clientY: 30, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [ + {clientX: 31, clientY: 30, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + }, + { + type: 'pointermove', + x: 50, + y: 45, + width: 1, + height: 1, + altitudeAngle: 1.5707963267948966, + azimuthAngle: 0, + pressure: 0.5, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchmove', + changedTouches: [ + {clientX: 50, clientY: 45, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [ + {clientX: 50, clientY: 45, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + }, + { + type: 'pointermove', + x: 80, + y: 50, + width: 1, + height: 1, + altitudeAngle: 1.5707963267948966, + azimuthAngle: 0, + pressure: 0.5, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchmove', + changedTouches: [ + {clientX: 80, clientY: 50, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [ + {clientX: 80, clientY: 50, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + }, + { + type: 'pointerup', + x: 80, + y: 50, + width: 1, + height: 1, + altitudeAngle: 1.5707963267948966, + azimuthAngle: 0, + pressure: 0, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchend', + changedTouches: [ + {clientX: 80, clientY: 50, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [], + }, + ]); }); }); }); diff --git a/remote/test/puppeteer/test/src/tracing.spec.ts b/remote/test/puppeteer/test/src/tracing.spec.ts index 2c0a5aff19..7ee6d46192 100644 --- a/remote/test/puppeteer/test/src/tracing.spec.ts +++ b/remote/test/puppeteer/test/src/tracing.spec.ts @@ -8,6 +8,8 @@ import fs from 'fs'; import path from 'path'; import expect from 'expect'; +import * as utils from 'puppeteer-core/internal/common/util.js'; +import sinon from 'sinon'; import {launch} from './mocha-utils.js'; @@ -113,16 +115,26 @@ describe('Tracing', function () { await page.tracing.start({screenshots: true}); await page.goto(server.PREFIX + '/grid.html'); - const oldBufferConcat = Buffer.concat; - try { - Buffer.concat = () => { - throw new Error('error'); - }; - const trace = await page.tracing.stop(); - expect(trace).toEqual(undefined); - } finally { - Buffer.concat = oldBufferConcat; - } + const oldGetReadableAsBuffer = utils.getReadableAsBuffer; + sinon.stub(utils, 'getReadableAsBuffer').callsFake(() => { + return oldGetReadableAsBuffer({ + getReader() { + return { + done: false, + read() { + if (!this.done) { + this.done = true; + return {done: false, value: 42}; + } + return {done: true}; + }, + }; + }, + } as unknown as ReadableStream); + }); + + const trace = await page.tracing.stop(); + expect(trace).toEqual(undefined); }); it('should support a buffer without a path', async () => { diff --git a/remote/test/puppeteer/test/src/waittask.spec.ts b/remote/test/puppeteer/test/src/waittask.spec.ts index 8ff52db16f..b9a28c9e7a 100644 --- a/remote/test/puppeteer/test/src/waittask.spec.ts +++ b/remote/test/puppeteer/test/src/waittask.spec.ts @@ -336,39 +336,6 @@ describe('waittask specs', function () { }); }); - describe('Page.waitForTimeout', () => { - it('waits for the given timeout before resolving', async () => { - const {page, server} = await getTestState(); - await page.goto(server.EMPTY_PAGE); - const startTime = Date.now(); - await page.waitForTimeout(1000); - const endTime = Date.now(); - /* In a perfect world endTime - startTime would be exactly 1000 but we - * expect some fluctuations and for it to be off by a little bit. So to - * avoid a flaky test we'll make sure it waited for roughly 1 second. - */ - expect(endTime - startTime).toBeGreaterThan(700); - expect(endTime - startTime).toBeLessThan(1300); - }); - }); - - describe('Frame.waitForTimeout', () => { - it('waits for the given timeout before resolving', async () => { - const {page, server} = await getTestState(); - await page.goto(server.EMPTY_PAGE); - const frame = page.mainFrame(); - const startTime = Date.now(); - await frame.waitForTimeout(1000); - const endTime = Date.now(); - /* In a perfect world endTime - startTime would be exactly 1000 but we - * expect some fluctuations and for it to be off by a little bit. So to - * avoid a flaky test we'll make sure it waited for roughly 1 second - */ - expect(endTime - startTime).toBeGreaterThan(700); - expect(endTime - startTime).toBeLessThan(1300); - }); - }); - describe('Frame.waitForSelector', function () { const addElement = (tag: string) => { return document.body.appendChild(document.createElement(tag)); @@ -479,9 +446,10 @@ describe('waittask specs', function () { await detachFrame(page, 'frame1'); await waitPromise; expect(waitError).toBeTruthy(); - expect(waitError?.message).toContain( - 'waitForFunction failed: frame got detached.' - ); + expect(waitError?.message).atLeastOneToContain([ + 'waitForFunction failed: frame got detached.', + 'Browsing context already closed.', + ]); }); it('should survive cross-process navigation', async () => { const {page, server} = await getTestState(); @@ -726,142 +694,151 @@ describe('waittask specs', function () { // The extension is ts here as Mocha maps back via sourcemaps. expect(error?.stack).toContain('WaitTask.ts'); }); - }); - describe('Frame.waitForXPath', function () { - const addElement = (tag: string) => { - return document.body.appendChild(document.createElement(tag)); - }; - - it('should support some fancy xpath', async () => { - const {page} = await getTestState(); + describe('xpath', function () { + const addElement = (tag: string) => { + return document.body.appendChild(document.createElement(tag)); + }; - await page.setContent(`<p>red herring</p><p>hello world </p>`); - const waitForXPath = page.waitForXPath( - '//p[normalize-space(.)="hello world"]' - ); - expect( - await page.evaluate( - x => { - return x?.textContent; - }, - await waitForXPath - ) - ).toBe('hello world '); - }); - it('should respect timeout', async () => { - const {page} = await getTestState(); + it('should support some fancy xpath', async () => { + const {page} = await getTestState(); - let error!: Error; - await page.waitForXPath('//div', {timeout: 10}).catch(error_ => { - return (error = error_); + await page.setContent(`<p>red herring</p><p>hello world </p>`); + const waitForSelector = page.waitForSelector( + 'xpath/.//p[normalize-space(.)="hello world"]' + ); + expect( + await page.evaluate( + x => { + return x?.textContent; + }, + await waitForSelector + ) + ).toBe('hello world '); }); - expect(error).toBeInstanceOf(TimeoutError); - expect(error?.message).toContain('Waiting failed: 10ms exceeded'); - }); - it('should run in specified frame', async () => { - const {page, server} = await getTestState(); + it('should respect timeout', async () => { + const {page} = await getTestState(); - await attachFrame(page, 'frame1', server.EMPTY_PAGE); - await attachFrame(page, 'frame2', server.EMPTY_PAGE); - const frame1 = page.frames()[1]!; - const frame2 = page.frames()[2]!; - const waitForXPathPromise = frame2.waitForXPath('//div'); - await frame1.evaluate(addElement, 'div'); - await frame2.evaluate(addElement, 'div'); - using eHandle = await waitForXPathPromise; - expect(eHandle?.frame).toBe(frame2); - }); - it('should throw when frame is detached', async () => { - const {page, server} = await getTestState(); - - await attachFrame(page, 'frame1', server.EMPTY_PAGE); - const frame = page.frames()[1]!; - let waitError: Error | undefined; - const waitPromise = frame - .waitForXPath('//*[@class="box"]') - .catch(error => { - return (waitError = error); - }); - await detachFrame(page, 'frame1'); - await waitPromise; - expect(waitError).toBeTruthy(); - expect(waitError?.message).toContain( - 'waitForFunction failed: frame got detached.' - ); - }); - it('hidden should wait for display: none', async () => { - const {page} = await getTestState(); - - let divHidden = false; - await page.setContent(`<div style='display: block;'>text</div>`); - const waitForXPath = page - .waitForXPath('//div', {hidden: true}) - .then(() => { - return (divHidden = true); + let error!: Error; + await page + .waitForSelector('xpath/.//div', {timeout: 10}) + .catch(error_ => { + return (error = error_); + }); + expect(error).toBeInstanceOf(TimeoutError); + expect(error?.message).toContain('Waiting failed: 10ms exceeded'); + }); + it('should run in specified frame', async () => { + const {page, server} = await getTestState(); + + await attachFrame(page, 'frame1', server.EMPTY_PAGE); + await attachFrame(page, 'frame2', server.EMPTY_PAGE); + const frame1 = page.frames()[1]!; + const frame2 = page.frames()[2]!; + const waitForSelector = frame2.waitForSelector('xpath/.//div'); + await frame1.evaluate(addElement, 'div'); + await frame2.evaluate(addElement, 'div'); + using eHandle = await waitForSelector; + expect(eHandle?.frame).toBe(frame2); + }); + it('should throw when frame is detached', async () => { + const {page, server} = await getTestState(); + + await attachFrame(page, 'frame1', server.EMPTY_PAGE); + const frame = page.frames()[1]!; + let waitError: Error | undefined; + const waitPromise = frame + .waitForSelector('xpath/.//*[@class="box"]') + .catch(error => { + return (waitError = error); + }); + await detachFrame(page, 'frame1'); + await waitPromise; + expect(waitError).toBeTruthy(); + expect(waitError?.message).atLeastOneToContain([ + 'waitForFunction failed: frame got detached.', + 'Browsing context already closed.', + ]); + }); + it('hidden should wait for display: none', async () => { + const {page} = await getTestState(); + + let divHidden = false; + await page.setContent(`<div style='display: block;'>text</div>`); + const waitForSelector = page + .waitForSelector('xpath/.//div', {hidden: true}) + .then(() => { + return (divHidden = true); + }); + await page.waitForSelector('xpath/.//div'); // do a round trip + expect(divHidden).toBe(false); + await page.evaluate(() => { + return document + .querySelector('div') + ?.style.setProperty('display', 'none'); }); - await page.waitForXPath('//div'); // do a round trip - expect(divHidden).toBe(false); - await page.evaluate(() => { - return document - .querySelector('div') - ?.style.setProperty('display', 'none'); + expect(await waitForSelector).toBe(true); + expect(divHidden).toBe(true); }); - expect(await waitForXPath).toBe(true); - expect(divHidden).toBe(true); - }); - it('hidden should return null if the element is not found', async () => { - const {page} = await getTestState(); + it('hidden should return null if the element is not found', async () => { + const {page} = await getTestState(); - using waitForXPath = await page.waitForXPath('//div', {hidden: true}); + using waitForSelector = await page.waitForSelector('xpath/.//div', { + hidden: true, + }); - expect(waitForXPath).toBe(null); - }); - it('hidden should return an empty element handle if the element is found', async () => { - const {page} = await getTestState(); + expect(waitForSelector).toBe(null); + }); + it('hidden should return an empty element handle if the element is found', async () => { + const {page} = await getTestState(); - await page.setContent(`<div style='display: none;'>text</div>`); + await page.setContent(`<div style='display: none;'>text</div>`); - using waitForXPath = await page.waitForXPath('//div', {hidden: true}); + using waitForSelector = await page.waitForSelector('xpath/.//div', { + hidden: true, + }); - expect(waitForXPath).toBeInstanceOf(ElementHandle); - }); - it('should return the element handle', async () => { - const {page} = await getTestState(); + expect(waitForSelector).toBeInstanceOf(ElementHandle); + }); + it('should return the element handle', async () => { + const {page} = await getTestState(); - const waitForXPath = page.waitForXPath('//*[@class="zombo"]'); - await page.setContent(`<div class='zombo'>anything</div>`); - expect( - await page.evaluate( - x => { - return x?.textContent; - }, - await waitForXPath - ) - ).toBe('anything'); - }); - it('should allow you to select a text node', async () => { - const {page} = await getTestState(); + const waitForSelector = page.waitForSelector( + 'xpath/.//*[@class="zombo"]' + ); + await page.setContent(`<div class='zombo'>anything</div>`); + expect( + await page.evaluate( + x => { + return x?.textContent; + }, + await waitForSelector + ) + ).toBe('anything'); + }); + it('should allow you to select a text node', async () => { + const {page} = await getTestState(); - await page.setContent(`<div>some text</div>`); - using text = await page.waitForXPath('//div/text()'); - expect(await (await text!.getProperty('nodeType')!).jsonValue()).toBe( - 3 /* Node.TEXT_NODE */ - ); - }); - it('should allow you to select an element with single slash', async () => { - const {page} = await getTestState(); + await page.setContent(`<div>some text</div>`); + using text = await page.waitForSelector('xpath/.//div/text()'); + expect(await (await text!.getProperty('nodeType')!).jsonValue()).toBe( + 3 /* Node.TEXT_NODE */ + ); + }); + it('should allow you to select an element with single slash', async () => { + const {page} = await getTestState(); - await page.setContent(`<div>some text</div>`); - const waitForXPath = page.waitForXPath('/html/body/div'); - expect( - await page.evaluate( - x => { - return x?.textContent; - }, - await waitForXPath - ) - ).toBe('some text'); + await page.setContent(`<div>some text</div>`); + const waitForSelector = page.waitForSelector('xpath/html/body/div'); + expect( + await page.evaluate( + x => { + return x?.textContent; + }, + await waitForSelector + ) + ).toBe('some text'); + }); }); }); }); diff --git a/remote/test/puppeteer/test/src/worker.spec.ts b/remote/test/puppeteer/test/src/worker.spec.ts index 254ff4a514..b5b7159e6a 100644 --- a/remote/test/puppeteer/test/src/worker.spec.ts +++ b/remote/test/puppeteer/test/src/worker.spec.ts @@ -52,7 +52,10 @@ describe('Workers', function () { const error = await workerThisObj.getProperty('self').catch(error => { return error; }); - expect(error.message).toContain('Most likely the worker has been closed.'); + expect(error.message).atLeastOneToContain([ + 'Most likely the worker has been closed.', + 'Realm already destroyed.', + ]); }); it('should report console logs', async () => { const {page} = await getTestState(); @@ -70,7 +73,7 @@ describe('Workers', function () { columnNumber: 8, }); }); - it('should have JSHandles for console logs', async () => { + it('should work with console logs', async () => { const {page} = await getTestState(); const logPromise = waitEvent<ConsoleMessage>(page, 'console'); @@ -80,9 +83,6 @@ describe('Workers', function () { const log = await logPromise; expect(log.text()).toBe('1 2 3 JSHandle@object'); expect(log.args()).toHaveLength(4); - expect(await (await log.args()[3]!.getProperty('origin')).jsonValue()).toBe( - 'null' - ); }); it('should have an execution context', async () => { const {page} = await getTestState(); @@ -106,4 +106,17 @@ describe('Workers', function () { const errorLog = await errorPromise; expect(errorLog.message).toContain('this is my error'); }); + + it('can be closed', async () => { + const {page, server} = await getTestState(); + + await Promise.all([ + waitEvent(page, 'workercreated'), + page.goto(server.PREFIX + '/worker/worker.html'), + ]); + const worker = page.workers()[0]!; + expect(worker?.url()).toContain('worker.js'); + + await Promise.all([waitEvent(page, 'workerdestroyed'), worker?.close()]); + }); }); diff --git a/remote/test/puppeteer/test/tsconfig.json b/remote/test/puppeteer/test/tsconfig.json index 554d034ff1..fdcd35374d 100644 --- a/remote/test/puppeteer/test/tsconfig.json +++ b/remote/test/puppeteer/test/tsconfig.json @@ -4,7 +4,7 @@ "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "build", - "rootDir": "src", + "rootDir": "src" }, - "include": ["src"], + "include": ["src"] } diff --git a/remote/test/puppeteer/tools/analyze_issue.mjs b/remote/test/puppeteer/tools/analyze_issue.mjs index 9592112de0..eff6a4122e 100755 --- a/remote/test/puppeteer/tools/analyze_issue.mjs +++ b/remote/test/puppeteer/tools/analyze_issue.mjs @@ -1,4 +1,10 @@ #!/usr/bin/env node +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + // @ts-check 'use strict'; diff --git a/remote/test/puppeteer/tools/clean.js b/remote/test/puppeteer/tools/clean.mjs index 049fdc0434..aa4ba516b1 100755 --- a/remote/test/puppeteer/tools/clean.js +++ b/remote/test/puppeteer/tools/clean.mjs @@ -1,7 +1,13 @@ #!/usr/bin/env node -const {exec} = require('child_process'); -const {readdirSync} = require('fs'); +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import {exec} from 'child_process'; +import {readdirSync} from 'fs'; exec( `git clean -Xf ${readdirSync(process.cwd()) diff --git a/remote/test/puppeteer/tools/docgen/package.json b/remote/test/puppeteer/tools/docgen/package.json index f1ca4ea127..82f6d4d6c4 100644 --- a/remote/test/puppeteer/tools/docgen/package.json +++ b/remote/test/puppeteer/tools/docgen/package.json @@ -8,7 +8,7 @@ "license": "Apache-2.0", "scripts": { "build": "wireit", - "clean": "../clean.js" + "clean": "../clean.mjs" }, "wireit": { "build": { @@ -24,10 +24,10 @@ } }, "devDependencies": { - "@microsoft/api-extractor": "7.39.4", - "@microsoft/api-documenter": "7.23.20", - "@microsoft/api-extractor-model": "7.28.7", + "@microsoft/api-extractor": "7.42.2", + "@microsoft/api-documenter": "7.23.35", + "@microsoft/api-extractor-model": "7.28.13", "@microsoft/tsdoc": "0.14.2", - "@rushstack/node-core-library": "3.64.2" + "@rushstack/node-core-library": "4.0.2" } } diff --git a/remote/test/puppeteer/tools/docgen/tsconfig.json b/remote/test/puppeteer/tools/docgen/tsconfig.json index fcaf1db737..27d0d84f5d 100644 --- a/remote/test/puppeteer/tools/docgen/tsconfig.json +++ b/remote/test/puppeteer/tools/docgen/tsconfig.json @@ -6,6 +6,6 @@ "sourceMap": true, "declaration": false, "declarationMap": false, - "composite": false, - }, + "composite": false + } } diff --git a/remote/test/puppeteer/tools/doctest/package.json b/remote/test/puppeteer/tools/doctest/package.json index 8c7e9544d0..1d0adb633b 100644 --- a/remote/test/puppeteer/tools/doctest/package.json +++ b/remote/test/puppeteer/tools/doctest/package.json @@ -8,7 +8,7 @@ "license": "Apache-2.0", "scripts": { "build": "wireit", - "clean": "../clean.js" + "clean": "../clean.mjs" }, "wireit": { "build": { @@ -24,7 +24,7 @@ } }, "devDependencies": { - "@swc/core": "1.3.107", + "@swc/core": "1.4.2", "@types/doctrine": "0.0.9", "@types/source-map-support": "0.5.10", "@types/yargs": "17.0.32", diff --git a/remote/test/puppeteer/tools/doctest/tsconfig.json b/remote/test/puppeteer/tools/doctest/tsconfig.json index bd70c0bd5e..6b8221571b 100644 --- a/remote/test/puppeteer/tools/doctest/tsconfig.json +++ b/remote/test/puppeteer/tools/doctest/tsconfig.json @@ -6,6 +6,6 @@ "sourceMap": true, "declaration": false, "declarationMap": false, - "composite": false, - }, + "composite": false + } } diff --git a/remote/test/puppeteer/tools/download_chrome_canary.mjs b/remote/test/puppeteer/tools/download_chrome_canary.mjs new file mode 100644 index 0000000000..9f523aea2a --- /dev/null +++ b/remote/test/puppeteer/tools/download_chrome_canary.mjs @@ -0,0 +1,51 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/* eslint-disable no-console */ + +/** + * @fileoverview Installs the latest Chrome Canary using + * `@puppeteer/browsers` to the directory provided as the first argument + * (default: cwd). The executable path is written to the `executablePath` output + * param for GitHub actions. + * + * Examples: + * + * - `node tools/download_chrome_canary.mjs` + * - `node tools/download_chrome_canary.mjs /tmp/cache` + */ +import actions from '@actions/core'; + +import { + Browser, + computeExecutablePath, + install, + resolveBuildId, + detectBrowserPlatform, +} from '@puppeteer/browsers'; + +try { + const cacheDir = process.argv[2] || process.cwd(); + const browser = Browser.CHROME; + const platform = detectBrowserPlatform(); + const buildId = await resolveBuildId(browser, platform, 'canary'); + await install({ + browser, + buildId, + cacheDir, + }); + const executablePath = computeExecutablePath({ + cacheDir, + browser, + buildId, + }); + if (process.argv.indexOf('--shell') === -1) { + actions.setOutput('executablePath', executablePath); + } + console.log(executablePath); +} catch (err) { + actions.setFailed(`Failed to download the browser: ${err.message}`); +} diff --git a/remote/test/puppeteer/tools/eslint/package.json b/remote/test/puppeteer/tools/eslint/package.json index 190367ae43..c7f7f4f38d 100644 --- a/remote/test/puppeteer/tools/eslint/package.json +++ b/remote/test/puppeteer/tools/eslint/package.json @@ -32,6 +32,7 @@ "author": "The Chromium Authors", "license": "Apache-2.0", "devDependencies": { - "@prettier/sync": "0.5.0" + "@prettier/sync": "0.5.1", + "@typescript-eslint/utils": "7.1.0" } } diff --git a/remote/test/puppeteer/tools/eslint/src/check-license.ts b/remote/test/puppeteer/tools/eslint/src/check-license.ts index 7ae1a54384..b8590a7c3f 100644 --- a/remote/test/puppeteer/tools/eslint/src/check-license.ts +++ b/remote/test/puppeteer/tools/eslint/src/check-license.ts @@ -11,15 +11,16 @@ const createRule = ESLintUtils.RuleCreator(name => { return `https://github.com/puppeteer/puppeteer/tree/main/tools/eslint/${name}.ts`; }); -const copyrightPattern = /Copyright ([0-9]{4}) Google Inc\./; +const currentYear = new Date().getFullYear(); -// const currentYear = new Date().getFullYear; - -// const licenseHeader = `/** -// * @license -// * Copyright ${currentYear} Google Inc. -// * SPDX-License-Identifier: Apache-2.0 -// */`; +// Needs to start and end with new line +const licenseHeader = ` +/** + * @license + * Copyright ${currentYear} Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +`; const enforceLicenseRule = createRule<[], 'licenseRule'>({ name: 'check-license', @@ -29,7 +30,7 @@ const enforceLicenseRule = createRule<[], 'licenseRule'>({ description: 'Validate existence of license header', requiresTypeChecking: false, }, - fixable: undefined, // TODO: change to 'code' once fixer works. + fixable: 'code', schema: [], messages: { licenseRule: 'Add license header.', @@ -39,40 +40,52 @@ const enforceLicenseRule = createRule<[], 'licenseRule'>({ create(context) { const sourceCode = context.sourceCode; const comments = sourceCode.getAllComments(); - const header = - comments[0]?.type === 'Block' && isHeaderComment(comments[0]) - ? comments[0] - : null; - - function isHeaderComment(comment: TSESTree.Comment) { - if (comment && comment.range[0] >= 0 && comment.range[1] <= 88) { - return true; - } else { - return false; + let insertAfter = [0, 0] as TSESTree.Range; + let header: TSESTree.Comment | null = null; + // Check only the first 2 comments + for (let index = 0; index < 2; index++) { + const comment = comments[index]; + if (!comment) { + break; + } + // Shebang comments should be at the top + if ( + // Types don't have it debugger showed it... + (comment.type as string) === 'Shebang' || + (comment.type === 'Line' && comment.value.startsWith('#!')) + ) { + insertAfter = comment.range; + continue; + } + if (comment.type === 'Block') { + header = comment; + break; } } return { Program(node) { + if (context.filename.endsWith('.json')) { + return; + } + if ( header && - header.value.includes('@license') && - header.value.includes('SPDX-License-Identifier: Apache-2.0') && - copyrightPattern.test(header.value) + (header.value.includes('@license') || + header.value.includes('License') || + header.value.includes('Copyright')) ) { return; } // Add header license if (!header || !header.value.includes('@license')) { - // const startLoc: [number, number] = [0, 88]; context.report({ node: node, messageId: 'licenseRule', - // TODO: fix the fixer. - // fix(fixer) { - // return fixer.insertTextBeforeRange(startLoc, licenseHeader); - // }, + fix(fixer) { + return fixer.insertTextAfterRange(insertAfter, licenseHeader); + }, }); } }, diff --git a/remote/test/puppeteer/tools/eslint/tsconfig.json b/remote/test/puppeteer/tools/eslint/tsconfig.json index da26cc936b..3a71788a21 100644 --- a/remote/test/puppeteer/tools/eslint/tsconfig.json +++ b/remote/test/puppeteer/tools/eslint/tsconfig.json @@ -7,8 +7,7 @@ "outDir": "./lib", "declaration": false, "declarationMap": false, - "sourceMap": false, "composite": false, - "removeComments": true, - }, + "removeComments": true + } } diff --git a/remote/test/puppeteer/tools/mocha-runner/package.json b/remote/test/puppeteer/tools/mocha-runner/package.json index 26612e504a..a817020d5e 100644 --- a/remote/test/puppeteer/tools/mocha-runner/package.json +++ b/remote/test/puppeteer/tools/mocha-runner/package.json @@ -9,7 +9,7 @@ "scripts": { "build": "wireit", "test": "wireit", - "clean": "../clean.js" + "clean": "../clean.mjs" }, "wireit": { "build": { diff --git a/remote/test/puppeteer/tools/mocha-runner/src/mocha-runner.ts b/remote/test/puppeteer/tools/mocha-runner/src/mocha-runner.ts index 1707e4cc41..93287abe74 100644 --- a/remote/test/puppeteer/tools/mocha-runner/src/mocha-runner.ts +++ b/remote/test/puppeteer/tools/mocha-runner/src/mocha-runner.ts @@ -52,7 +52,7 @@ const { .scriptName('@puppeteer/mocha-runner') .option('coverage', { boolean: true, - default: true, + default: false, }) .option('suggestions', { boolean: true, diff --git a/remote/test/puppeteer/tools/mocha-runner/tsconfig.json b/remote/test/puppeteer/tools/mocha-runner/tsconfig.json index 73a1b17815..220a467ac1 100644 --- a/remote/test/puppeteer/tools/mocha-runner/tsconfig.json +++ b/remote/test/puppeteer/tools/mocha-runner/tsconfig.json @@ -8,6 +8,6 @@ "sourceMap": true, "declaration": false, "declarationMap": false, - "composite": false, - }, + "composite": false + } } diff --git a/remote/test/puppeteer/tools/sort-test-expectations.mjs b/remote/test/puppeteer/tools/sort-test-expectations.mjs index d1c8588d8a..972d244874 100644 --- a/remote/test/puppeteer/tools/sort-test-expectations.mjs +++ b/remote/test/puppeteer/tools/sort-test-expectations.mjs @@ -13,9 +13,22 @@ import prettier from 'prettier'; const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); const source = 'test/TestExpectations.json'; -const testExpectations = JSON.parse(fs.readFileSync(source, 'utf-8')); +let testExpectations = JSON.parse(fs.readFileSync(source, 'utf-8')); const committedExpectations = structuredClone(testExpectations); +function testIdMatchesExpectationPattern(title, pattern) { + const patternRegExString = pattern + // Replace `*` with non special character + .replace(/\*/g, '--STAR--') + // Escape special characters https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + // Replace placeholder with greedy match + .replace(/--STAR--/g, '(.*)?'); + // Match beginning and end explicitly + const patternRegEx = new RegExp(`^${patternRegExString}$`); + return patternRegEx.test(title); +} + const prettierConfig = await import( path.join(__dirname, '..', '.prettierrc.cjs') ); @@ -43,9 +56,80 @@ testExpectations.forEach(item => { item.parameters.sort(); item.expectations.sort(); item.platforms.sort(); + // Delete comments for PASS expectations. They are likely outdated. + if (item.expectations.length === 1 && item.expectations[0] === 'PASS') { + delete item.comment; + } +}); + +function isSubset(superset, subset) { + let isSubset = true; + + for (const p of subset) { + if (!superset.has(p)) { + isSubset = false; + } + } + + return isSubset; +} + +const toBeRemoved = new Set(); +for (let i = testExpectations.length - 1; i >= 0; i--) { + const expectation = testExpectations[i]; + const params = new Set(expectation.parameters); + const labels = new Set(expectation.expectations); + const platforms = new Set(expectation.platforms); + + let foundMatch = false; + for (let j = i - 1; j >= 0; j--) { + const candidate = testExpectations[j]; + const candidateParams = new Set(candidate.parameters); + const candidateLabels = new Set(candidate.expectations); + const candidatePlatforms = new Set(candidate.platforms); + + if ( + testIdMatchesExpectationPattern( + expectation.testIdPattern, + candidate.testIdPattern + ) && + isSubset(candidateParams, params) && + isSubset(candidatePlatforms, platforms) + ) { + foundMatch = true; + if (isSubset(candidateLabels, labels)) { + console.log('removing', expectation, 'already covered by', candidate); + toBeRemoved.add(expectation); + } + break; + } + } + + if (!foundMatch && isSubset(new Set(['PASS']), labels)) { + console.log( + 'removing', + expectation, + 'because the default expectation is to pass' + ); + toBeRemoved.add(expectation); + } +} + +testExpectations = testExpectations.filter(item => { + return !toBeRemoved.has(item); }); if (process.argv.includes('--lint')) { + const missingComments = []; + testExpectations.forEach(item => { + if (item.expectations.length === 1 && item.expectations[0] === 'PASS') { + return; + } + if (!item.comment) { + missingComments.push(item); + } + }); + if ( JSON.stringify(committedExpectations) !== JSON.stringify(testExpectations) ) { @@ -54,6 +138,14 @@ if (process.argv.includes('--lint')) { ); process.exit(1); } + + if (missingComments.length > 0) { + console.error( + `${source}: missing comments for the following expectations:`, + missingComments + ); + process.exit(1); + } } else { fs.writeFileSync( source, diff --git a/remote/test/puppeteer/tools/tsconfig.json b/remote/test/puppeteer/tools/tsconfig.json index 964d349435..393392c494 100644 --- a/remote/test/puppeteer/tools/tsconfig.json +++ b/remote/test/puppeteer/tools/tsconfig.json @@ -1,4 +1,4 @@ { "extends": "../tsconfig.base.json", - "files": ["../package.json"], + "files": ["../package.json"] } diff --git a/remote/test/puppeteer/versions.js b/remote/test/puppeteer/versions.js index cbd835efc6..05d8429789 100644 --- a/remote/test/puppeteer/versions.js +++ b/remote/test/puppeteer/versions.js @@ -7,6 +7,9 @@ const versionsPerRelease = new Map([ // This is a mapping from Chrome version => Puppeteer version. // In Chrome roll patches, use `NEXT` for the Puppeteer version. + ['122.0.6261.94', 'v22.4.0'], + ['122.0.6261.69', 'v22.3.0'], + ['122.0.6261.57', 'v22.2.0'], ['121.0.6167.85', 'v21.9.0'], ['120.0.6099.109', 'v21.8.0'], ['119.0.6045.105', 'v21.5.0'], diff --git a/remote/webdriver-bidi/modules/root/browsingContext.sys.mjs b/remote/webdriver-bidi/modules/root/browsingContext.sys.mjs index bc600e89cd..f2a5d5e645 100644 --- a/remote/webdriver-bidi/modules/root/browsingContext.sys.mjs +++ b/remote/webdriver-bidi/modules/root/browsingContext.sys.mjs @@ -232,11 +232,27 @@ class BrowsingContextModule extends Module { ); } - const tab = lazy.TabManager.getTabForBrowsingContext(context); - const window = lazy.TabManager.getWindowForTab(tab); + const targetTab = lazy.TabManager.getTabForBrowsingContext(context); + const targetWindow = lazy.TabManager.getWindowForTab(targetTab); + const selectedTab = lazy.TabManager.getTabBrowser(targetWindow).selectedTab; + + const activated = [ + lazy.windowManager.focusWindow(targetWindow), + lazy.TabManager.selectTab(targetTab), + ]; - await lazy.windowManager.focusWindow(window); - await lazy.TabManager.selectTab(tab); + if (targetTab !== selectedTab && !lazy.AppInfo.isAndroid) { + // We need to wait until the "document.visibilityState" of the currently + // selected tab in the target window is marked as "hidden". + // + // Bug 1884142: It's not supported on Android for the TestRunner package. + const selectedBrowser = lazy.TabManager.getBrowserForTab(selectedTab); + activated.push( + this.#waitForVisibilityChange(selectedBrowser.browsingContext) + ); + } + + await Promise.all(activated); } /** @@ -532,33 +548,58 @@ class BrowsingContextModule extends Module { const type = lazy.AppInfo.isAndroid ? "tab" : typeHint; switch (type) { - case "window": + case "window": { const newWindow = await lazy.windowManager.openBrowserWindow({ focus: !background, userContextId: userContext, }); browser = lazy.TabManager.getTabBrowser(newWindow).selectedBrowser; break; - - case "tab": + } + case "tab": { if (!lazy.TabManager.supportsTabs()) { throw new lazy.error.UnsupportedOperationError( `browsingContext.create with type "tab" not supported in ${lazy.AppInfo.name}` ); } + // The window to open the new tab in. + let window = Services.wm.getMostRecentWindow(null); + let referenceTab; if (referenceContext !== null) { referenceTab = lazy.TabManager.getTabForBrowsingContext(referenceContext); + window = lazy.TabManager.getWindowForTab(referenceTab); } - const tab = await lazy.TabManager.addTab({ - focus: !background, - referenceTab, - userContextId: userContext, - }); + const promises = []; + + if (!background && !lazy.AppInfo.isAndroid) { + // When opening a new foreground tab we need to wait until the + // "document.visibilityState" of the currently selected tab in this + // window is marked as "hidden". + // + // Bug 1884142: It's not supported on Android for the TestRunner package. + const selectedTab = lazy.TabManager.getTabBrowser(window).selectedTab; + promises.push( + this.#waitForVisibilityChange( + lazy.TabManager.getBrowserForTab(selectedTab).browsingContext + ) + ); + } + + promises.unshift( + lazy.TabManager.addTab({ + focus: !background, + referenceTab, + userContextId: userContext, + }) + ); + + const [tab] = await Promise.all(promises); browser = lazy.TabManager.getBrowserForTab(tab); + } } await lazy.waitForInitialNavigationCompleted( @@ -1918,6 +1959,21 @@ class BrowsingContextModule extends Module { } } + #waitForVisibilityChange(browsingContext) { + return this.messageHandler.forwardCommand({ + moduleName: "browsingContext", + commandName: "_awaitVisibilityState", + destination: { + type: lazy.WindowGlobalMessageHandler.type, + id: browsingContext.id, + }, + params: { + value: "hidden", + }, + retryOnAbort: true, + }); + } + /** * Internal commands */ diff --git a/remote/webdriver-bidi/modules/root/input.sys.mjs b/remote/webdriver-bidi/modules/root/input.sys.mjs index 8edd8299b7..0764ac3f92 100644 --- a/remote/webdriver-bidi/modules/root/input.sys.mjs +++ b/remote/webdriver-bidi/modules/root/input.sys.mjs @@ -91,6 +91,63 @@ class InputModule extends Module { return {}; } + /** + * Sets the file property of a given input element with type file to a set of file paths. + * + * @param {object=} options + * @param {string} options.context + * Id of the browsing context to set the file property + * of a given input element. + * @param {SharedReference} options.element + * A reference to a node, which is used as + * a target for setting files. + * @param {Array<string>} options.files + * A list of file paths which should be set. + * + * @throws {InvalidArgumentError} + * Raised if an argument is of an invalid type or value. + * @throws {NoSuchElementError} + * If the input element cannot be found. + * @throws {NoSuchFrameError} + * If the browsing context cannot be found. + * @throws {UnableToSetFileInputError} + * If the set of file paths was not set to the input element. + */ + async setFiles(options = {}) { + const { context: contextId, element, files } = options; + + lazy.assert.string( + contextId, + `Expected "context" to be a string, got ${contextId}` + ); + + const context = lazy.TabManager.getBrowsingContextById(contextId); + if (!context) { + throw new lazy.error.NoSuchFrameError( + `Browsing context with id ${contextId} not found` + ); + } + + lazy.assert.array(files, `Expected "files" to be an array, got ${files}`); + + for (const file of files) { + lazy.assert.string( + file, + `Expected an element of "files" to be a string, got ${file}` + ); + } + + await this.messageHandler.forwardCommand({ + moduleName: "input", + commandName: "setFiles", + destination: { + type: lazy.WindowGlobalMessageHandler.type, + id: context.id, + }, + params: { element, files }, + }); + } + static get supportedEvents() { return []; } diff --git a/remote/webdriver-bidi/modules/root/storage.sys.mjs b/remote/webdriver-bidi/modules/root/storage.sys.mjs index 50fbd8ecd6..3eced2da4c 100644 --- a/remote/webdriver-bidi/modules/root/storage.sys.mjs +++ b/remote/webdriver-bidi/modules/root/storage.sys.mjs @@ -12,6 +12,8 @@ ChromeUtils.defineESModuleGetters(lazy, { "chrome://remote/content/webdriver-bidi/modules/root/network.sys.mjs", error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs", TabManager: "chrome://remote/content/shared/TabManager.sys.mjs", + UserContextManager: + "chrome://remote/content/shared/UserContextManager.sys.mjs", }); const CookieFieldsMapping = { @@ -96,14 +98,14 @@ class StorageModule extends Module { * * @property {PartitionType} [type=PartitionType.storageKey] * @property {string=} sourceOrigin - * @property {string=} userContext (not supported) + * @property {string=} userContext */ /** * @typedef PartitionKey * * @property {string=} sourceOrigin - * @property {string=} userContext (not supported) + * @property {string=} userContext */ /** @@ -119,6 +121,48 @@ class StorageModule extends Module { */ /** + * Remove zero or more cookies which match a set of provided parameters. + * + * @param {object=} options + * @param {CookieFilter=} options.filter + * An object which holds field names and values, which + * should be used to filter the output of the command. + * @param {PartitionDescriptor=} options.partition + * An object which holds the information which + * should be used to build a partition key. + * + * @returns {PartitionKey} + * An object with the partition key which was used to + * retrieve cookies which had to be removed. + * @throws {InvalidArgumentError} + * If the provided arguments are not valid. + * @throws {NoSuchFrameError} + * If the provided browsing context cannot be found. + */ + async deleteCookies(options = {}) { + let { filter = {} } = options; + const { partition: partitionSpec = null } = options; + + this.#assertPartition(partitionSpec); + filter = this.#assertCookieFilter(filter); + + const partitionKey = this.#expandStoragePartitionSpec(partitionSpec); + const store = this.#getTheCookieStore(partitionKey); + const cookies = this.#getMatchingCookies(store, filter); + + for (const cookie of cookies) { + Services.cookies.remove( + cookie.host, + cookie.name, + cookie.path, + cookie.originAttributes + ); + } + + return { partitionKey: this.#formatPartitionKey(partitionKey) }; + } + + /** * Retrieve zero or more cookies which match a set of provided parameters. * * @param {object=} options @@ -136,27 +180,27 @@ class StorageModule extends Module { * If the provided arguments are not valid. * @throws {NoSuchFrameError} * If the provided browsing context cannot be found. - * @throws {UnsupportedOperationError} - * Raised when the command is called with `userContext` as - * in `partition` argument. */ async getCookies(options = {}) { let { filter = {} } = options; const { partition: partitionSpec = null } = options; this.#assertPartition(partitionSpec); - filter = this.#assertGetCookieFilter(filter); + filter = this.#assertCookieFilter(filter); const partitionKey = this.#expandStoragePartitionSpec(partitionSpec); const store = this.#getTheCookieStore(partitionKey); const cookies = this.#getMatchingCookies(store, filter); + const serializedCookies = []; - // Bug 1875255. Exchange platform id for Webdriver BiDi id for the user context to return it to the client. - // For now we use platform user context id for returning cookies for a specific browsing context in the platform API, - // but we can not return it directly to the client, so for now we just remove it from the response. - delete partitionKey.userContext; + for (const cookie of cookies) { + serializedCookies.push(this.#serializeCookie(cookie)); + } - return { cookies, partitionKey }; + return { + cookies: serializedCookies, + partitionKey: this.#formatPartitionKey(partitionKey), + }; } /** @@ -195,9 +239,6 @@ class StorageModule extends Module { * If the provided browsing context cannot be found. * @throws {UnableToSetCookieError} * If the cookie was not added. - * @throws {UnsupportedOperationError} - * Raised when the command is called with `userContext` as - * in `partition` argument. */ async setCookie(options = {}) { const { cookie: cookieSpec, partition: partitionSpec = null } = options; @@ -264,12 +305,7 @@ class StorageModule extends Module { throw new lazy.error.UnableToSetCookieError(e); } - // Bug 1875255. Exchange platform id for Webdriver BiDi id for the user context to return it to the client. - // For now we use platform user context id for returning cookies for a specific browsing context in the platform API, - // but we can not return it directly to the client, so for now we just remove it from the response. - delete partitionKey.userContext; - - return { partitionKey }; + return { partitionKey: this.#formatPartitionKey(partitionKey) }; } #assertCookie(cookie) { @@ -318,7 +354,7 @@ class StorageModule extends Module { } } - #assertGetCookieFilter(filter) { + #assertCookieFilter(filter) { lazy.assert.object( filter, `Expected "filter" to be an object, got ${filter}` @@ -454,10 +490,11 @@ class StorageModule extends Module { `Expected "partition.userContext" to be a string, got ${userContext}` ); - // TODO: Bug 1875255. Implement support for "userContext" field. - throw new lazy.error.UnsupportedOperationError( - `"userContext" as a field on "partition" argument is not supported yet for "storage.getCookies" command` - ); + if (!lazy.UserContextManager.hasUserContextId(userContext)) { + throw new lazy.error.NoSuchUserContextError( + `User Context with id ${userContext} was not found` + ); + } } break; } @@ -505,6 +542,40 @@ class StorageModule extends Module { } /** + * Deserialize filter. + * + * @see https://w3c.github.io/webdriver-bidi/#deserialize-filter + */ + #deserializeFilter(filter) { + const deserializedFilter = {}; + for (const [fieldName, value] of Object.entries(filter)) { + if (value === null) { + continue; + } + + const deserializedName = CookieFieldsMapping[fieldName]; + let deserializedValue; + + switch (deserializedName) { + case "sameSite": + deserializedValue = this.#getSameSitePlatformProperty(value); + break; + + case "value": + deserializedValue = this.#deserializeProtocolBytes(value); + break; + + default: + deserializedValue = value; + } + + deserializedFilter[deserializedName] = deserializedValue; + } + + return deserializedFilter; + } + + /** * Deserialize the value to string, since platform API * returns cookie's value as a string. */ @@ -544,7 +615,14 @@ class StorageModule extends Module { const partitionKey = {}; for (const keyName of PartitionKeyAttributes) { if (keyName in partitionSpec) { - partitionKey[keyName] = partitionSpec[keyName]; + // Retrieve a platform user context id. + if (keyName === "userContext") { + partitionKey[keyName] = lazy.UserContextManager.getInternalIdById( + partitionSpec.userContext + ); + } else { + partitionKey[keyName] = partitionSpec[keyName]; + } } } @@ -552,6 +630,20 @@ class StorageModule extends Module { } /** + * Prepare the partition key in the right format for returning to a client. + */ + #formatPartitionKey(partitionKey) { + if ("userContext" in partitionKey) { + // Exchange platform id for Webdriver BiDi id for the user context to return it to the client. + partitionKey.userContext = lazy.UserContextManager.getIdByInternalId( + partitionKey.userContext + ); + } + + return partitionKey; + } + + /** * Retrieves a browsing context based on its id. * * @param {number} contextId @@ -595,11 +687,11 @@ class StorageModule extends Module { */ #getMatchingCookies(cookieStore, filter) { const cookies = []; + const deserializedFilter = this.#deserializeFilter(filter); for (const storedCookie of cookieStore) { - const serializedCookie = this.#serializeCookie(storedCookie); - if (this.#matchCookie(serializedCookie, filter)) { - cookies.push(serializedCookie); + if (this.#matchCookie(storedCookie, deserializedFilter)) { + cookies.push(storedCookie); } } return cookies; @@ -649,18 +741,14 @@ class StorageModule extends Module { // Prepare the data in the format required for the platform API. const originAttributes = this.#getOriginAttributes(storagePartitionKey); - // In case we want to get the cookies for a certain `sourceOrigin`, - // we have to additionally specify `hostname`. When `sourceOrigin` is not present - // `hostname` will stay equal undefined. - let hostname; // In case we want to get the cookies for a certain `sourceOrigin`, // we have to separately retrieve cookies for a hostname built from `sourceOrigin`, // and with `partitionKey` equal an empty string to retrieve the cookies that which were set - // by this hostname but without `partitionKey`, e.g. with `document.cookie` + // by this hostname but without `partitionKey`, e.g. with `document.cookie`. if (storagePartitionKey.sourceOrigin) { const url = new URL(storagePartitionKey.sourceOrigin); - hostname = url.hostname; + const hostname = url.hostname; const principal = Services.scriptSecurityManager.createContentPrincipal( Services.io.newURI(url), @@ -688,8 +776,7 @@ class StorageModule extends Module { // Add the cookies which exactly match a built partition attributes. store = store.concat( Services.cookies.getCookiesWithOriginAttributes( - JSON.stringify(originAttributes), - hostname + JSON.stringify(originAttributes) ) ); @@ -702,19 +789,23 @@ class StorageModule extends Module { * @see https://w3c.github.io/webdriver-bidi/#match-cookie */ #matchCookie(storedCookie, filter) { - for (const [fieldName] of Object.entries(CookieFieldsMapping)) { - let value = filter[fieldName]; - if (value !== null) { - let storedCookieValue = storedCookie[fieldName]; - - if (fieldName === "value") { - value = this.#deserializeProtocolBytes(value); - storedCookieValue = this.#deserializeProtocolBytes(storedCookieValue); - } + for (const [fieldName, value] of Object.entries(filter)) { + // Since we set `null` to not specified values, we have to check for `null` here + // and not match on these values. + if (value === null) { + continue; + } - if (storedCookieValue !== value) { - return false; - } + let storedCookieValue = storedCookie[fieldName]; + + // The platform represantation of cookie doesn't contain a size field, + // so we have to calculate it to match. + if (fieldName === "size") { + storedCookieValue = this.#getCookieSize(storedCookie); + } + + if (storedCookieValue !== value) { + return false; } } diff --git a/remote/webdriver-bidi/modules/windowglobal/browsingContext.sys.mjs b/remote/webdriver-bidi/modules/windowglobal/browsingContext.sys.mjs index 8421445d2c..adf821601d 100644 --- a/remote/webdriver-bidi/modules/windowglobal/browsingContext.sys.mjs +++ b/remote/webdriver-bidi/modules/windowglobal/browsingContext.sys.mjs @@ -17,6 +17,7 @@ ChromeUtils.defineESModuleGetters(lazy, { "chrome://remote/content/webdriver-bidi/modules/root/browsingContext.sys.mjs", OriginType: "chrome://remote/content/webdriver-bidi/modules/root/browsingContext.sys.mjs", + PollPromise: "chrome://remote/content/shared/Sync.sys.mjs", }); const DOCUMENT_FRAGMENT_NODE = 11; @@ -356,6 +357,29 @@ class BrowsingContextModule extends WindowGlobalBiDiModule { }); } + /** + * Waits until the visibility state of the document has the expected value. + * + * @param {object} options + * @param {number} options.value + * Expected value of the visibility state. + * + * @returns {Promise} + * Promise that resolves when the visibility state has the expected value. + */ + async _awaitVisibilityState(options) { + const { value } = options; + const win = this.messageHandler.window; + + await lazy.PollPromise((resolve, reject) => { + if (win.document.visibilityState === value) { + resolve(); + } else { + reject(); + } + }); + } + _getBaseURL() { return this.messageHandler.window.document.baseURI; } diff --git a/remote/webdriver-bidi/modules/windowglobal/input.sys.mjs b/remote/webdriver-bidi/modules/windowglobal/input.sys.mjs index 099cf53d46..b91cce2310 100644 --- a/remote/webdriver-bidi/modules/windowglobal/input.sys.mjs +++ b/remote/webdriver-bidi/modules/windowglobal/input.sys.mjs @@ -10,6 +10,7 @@ ChromeUtils.defineESModuleGetters(lazy, { action: "chrome://remote/content/shared/webdriver/Actions.sys.mjs", dom: "chrome://remote/content/shared/DOM.sys.mjs", error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs", + event: "chrome://remote/content/shared/webdriver/Event.sys.mjs", }); class InputModule extends WindowGlobalBiDiModule { @@ -43,6 +44,67 @@ class InputModule extends WindowGlobalBiDiModule { this.#actionState = null; } + async setFiles(options) { + const { element: sharedReference, files } = options; + + const element = await this.#deserializeElementSharedReference( + sharedReference + ); + + if ( + !HTMLInputElement.isInstance(element) || + element.type !== "file" || + element.disabled + ) { + throw new lazy.error.UnableToSetFileInputError( + `Element needs to be an <input> element with type "file" and not disabled` + ); + } + + if (files.length > 1 && !element.hasAttribute("multiple")) { + throw new lazy.error.UnableToSetFileInputError( + `Element should have an attribute "multiple" set when trying to set more than 1 file` + ); + } + + const fileObjects = []; + for (const file of files) { + try { + fileObjects.push(await File.createFromFileName(file)); + } catch (e) { + throw new lazy.error.InvalidArgumentError( + `Failed to add file ${file} (${e})` + ); + } + } + + const selectedFiles = Array.from(element.files); + + const intersection = fileObjects.filter(fileObject => + selectedFiles.some( + selectedFile => + // Compare file fields to identify if the files are equal. + // TODO: Bug 1883856. Add check for full path or use a different way + // to compare files when it's available. + selectedFile.name === fileObject.name && + selectedFile.size === fileObject.size && + selectedFile.type === fileObject.type + ) + ); + + if ( + intersection.length === selectedFiles.length && + selectedFiles.length === fileObjects.length + ) { + lazy.event.cancel(element); + } else { + element.mozSetFileArray(fileObjects); + + lazy.event.input(element); + lazy.event.change(element); + } + } + /** * In the provided array of input.SourceActions, replace all origins matching * the input.ElementOrigin production with the Element corresponding to this @@ -75,8 +137,8 @@ class InputModule extends WindowGlobalBiDiModule { if (action?.origin?.type === "element") { promises.push( (async () => { - action.origin = await this.#getElementFromElementOrigin( - action.origin + action.origin = await this.#deserializeElementSharedReference( + action.origin.element ); })() ); @@ -87,11 +149,10 @@ class InputModule extends WindowGlobalBiDiModule { return Promise.all(promises); } - async #getElementFromElementOrigin(origin) { - const sharedReference = origin.element; + async #deserializeElementSharedReference(sharedReference) { if (typeof sharedReference?.sharedId !== "string") { throw new lazy.error.InvalidArgumentError( - `Expected "origin.element" to be a SharedReference, got: ${sharedReference}` + `Expected "element" to be a SharedReference, got: ${sharedReference}` ); } diff --git a/remote/webdriver-bidi/modules/windowglobal/script.sys.mjs b/remote/webdriver-bidi/modules/windowglobal/script.sys.mjs index e0f9542bdd..88d58f8064 100644 --- a/remote/webdriver-bidi/modules/windowglobal/script.sys.mjs +++ b/remote/webdriver-bidi/modules/windowglobal/script.sys.mjs @@ -290,7 +290,7 @@ class ScriptModule extends WindowGlobalBiDiModule { const rawObject = maybeDebuggerObject.unsafeDereference(); // TODO: Getters for Maps and Sets iterators return "Opaque" objects and - // are not iterable. RemoteValue.jsm' serializer should handle calling + // are not iterable. RemoteValue.sys.mjs' serializer should handle calling // waiveXrays on Maps/Sets/... and then unwaiveXrays on entries but since // we serialize with maxDepth=1, calling waiveXrays once on the root // object allows to return correctly serialized values. |