From 48c0a37886ff0ce6a11bc90e96f695dcac64ede1 Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Thu, 26 Sep 2024 13:03:13 -0400 Subject: [PATCH 01/22] misc: implement webdriver npm package as the client for the webdriver specification --- package.json | 2 + packages/server/lib/browsers/firefox-util.ts | 18 +- packages/server/lib/browsers/firefox.ts | 112 +++-- .../README.md => firefox_automation.md} | 28 +- .../server/lib/browsers/geckodriver/index.ts | 122 ----- .../lib/browsers/webdriver-classic/index.ts | 263 ---------- .../server/lib/browsers/webdriver/index.ts | 38 ++ packages/server/package.json | 6 +- .../patches/@wdio+protocols+9.0.0.patch | 79 +++ .../server/patches/@wdio+utils+9.0.0.patch | 31 ++ ...er+4.4.2.patch => geckodriver+4.5.0.patch} | 75 +-- packages/server/patches/webdriver+9.0.0.patch | 199 ++++++++ .../server/test/unit/browsers/firefox_spec.ts | 453 ++++++++++-------- .../unit/browsers/geckodriver/index_spec.ts | 242 ---------- .../browsers/webdriver-classic/index_spec.ts | 316 ------------ .../cache/darwin/snapshot-meta.json | 36 +- yarn.lock | 259 ++++++++-- 17 files changed, 970 insertions(+), 1309 deletions(-) rename packages/server/lib/browsers/{geckodriver/README.md => firefox_automation.md} (55%) delete mode 100644 packages/server/lib/browsers/geckodriver/index.ts delete mode 100644 packages/server/lib/browsers/webdriver-classic/index.ts create mode 100644 packages/server/lib/browsers/webdriver/index.ts create mode 100644 packages/server/patches/@wdio+protocols+9.0.0.patch create mode 100644 packages/server/patches/@wdio+utils+9.0.0.patch rename packages/server/patches/{geckodriver+4.4.2.patch => geckodriver+4.5.0.patch} (77%) create mode 100644 packages/server/patches/webdriver+9.0.0.patch delete mode 100644 packages/server/test/unit/browsers/geckodriver/index_spec.ts delete mode 100644 packages/server/test/unit/browsers/webdriver-classic/index_spec.ts diff --git a/package.json b/package.json index 8f6aeb311e83..ae8e9e8119af 100644 --- a/package.json +++ b/package.json @@ -245,6 +245,7 @@ "scripts" ], "nohoist": [ + "**/@wdio/*", "**/webpack-preprocessor/babel-loader", "**/webpack-preprocessor/**/merge-source-map", "**/webpack-preprocessor/**/patch-package", @@ -262,6 +263,7 @@ "**/@types/cheerio": "0.22.21", "**/@types/enzyme": "3.10.5", "**/@types/react": "16.9.50", + "**/@wdio/logger": "9.0.0", "**/jquery": "3.4.1", "**/pretty-format": "26.4.0", "**/sharp": "0.29.3", diff --git a/packages/server/lib/browsers/firefox-util.ts b/packages/server/lib/browsers/firefox-util.ts index 40d0828c24f3..07ec85c45caa 100644 --- a/packages/server/lib/browsers/firefox-util.ts +++ b/packages/server/lib/browsers/firefox-util.ts @@ -6,9 +6,9 @@ import Foxdriver from '@benmalka/foxdriver' import * as protocol from './protocol' import { CdpAutomation } from './cdp_automation' import { BrowserCriClient } from './browser-cri-client' +import type { Client as WebDriverClient } from 'webdriver' import type { Automation } from '../automation' import type { CypressError } from '@packages/errors' -import type { WebDriverClassic } from './webdriver-classic' const debug = Debug('cypress:server:browsers:firefox-util') @@ -20,7 +20,7 @@ let timings = { collections: [] as any[], } -let webDriverClassic: WebDriverClassic +let webdriverClient: WebDriverClient const getTabId = (tab) => { return _.get(tab, 'browsingContextID') @@ -103,11 +103,11 @@ async function connectToNewTabClassic () { // For versions 124 and above, a new tab is not created, so @packages/extension creates one for us. // Since the tab is always available on our behalf, // we can connect to it here and navigate it to about:blank to set it up for CDP connection - const handles = await webDriverClassic.getWindowHandles() + const handles = await webdriverClient.getWindowHandles() - await webDriverClassic.switchToWindow(handles[0]) + await webdriverClient.switchToWindow(handles[0]) - await webDriverClassic.navigate('about:blank') + await webdriverClient.navigateTo('about:blank') } async function connectToNewSpec (options, automation: Automation, browserCriClient: BrowserCriClient) { @@ -140,7 +140,7 @@ async function setupCDP (remotePort: number, automation: Automation, onError?: ( } async function navigateToUrlClassic (url: string) { - await webDriverClassic.navigate(url) + await webdriverClient.navigateTo(url) } const logGcDetails = () => { @@ -213,17 +213,17 @@ export default { url, foxdriverPort, remotePort, - webDriverClassic: wdcInstance, + webdriverClient: wdInstance, }: { automation: Automation onError?: (err: Error) => void url: string foxdriverPort: number remotePort: number - webDriverClassic: WebDriverClassic + webdriverClient: WebDriverClient }): Promise { // set the WebDriver classic instance instantiated from geckodriver - webDriverClassic = wdcInstance + webdriverClient = wdInstance const [, browserCriClient] = await Promise.all([ this.setupFoxdriver(foxdriverPort), setupCDP(remotePort, automation, onError), diff --git a/packages/server/lib/browsers/firefox.ts b/packages/server/lib/browsers/firefox.ts index c1cfc9a88139..daa6f1fce0f4 100644 --- a/packages/server/lib/browsers/firefox.ts +++ b/packages/server/lib/browsers/firefox.ts @@ -1,4 +1,5 @@ import _ from 'lodash' +import EventEmitter from 'events' import fs from 'fs-extra' import Debug from 'debug' import getPort from 'get-port' @@ -18,12 +19,15 @@ import type { Automation } from '../automation' import { getCtx } from '@packages/data-context' import { getError } from '@packages/errors' import type { BrowserLaunchOpts, BrowserNewTabOpts, RunModeVideoApi } from '@packages/types' -import { GeckoDriver } from './geckodriver' -import { WebDriverClassic } from './webdriver-classic' +import type { RemoteConfig } from 'webdriver' +import { GeckoDriverOptions, WebDriver } from './webdriver' const debug = Debug('cypress:server:browsers:firefox') const debugVerbose = Debug('cypress-verbose:server:browsers:firefox') +const WEBDRIVER_DEBUG_NAMESPACE_VERBOSE = 'cypress-verbose:server:browsers:webdriver' +const GECKODRIVER_DEBUG_NAMESPACE_VERBOSE = 'cypress-verbose:server:browsers:geckodriver' + // used to prevent the download prompt for the specified file types. // this should cover most/all file types, but if it's necessary to // discover more, open Firefox DevTools, download the file yourself @@ -443,16 +447,15 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc const [ foxdriverPort, marionettePort, - geckoDriverPort, webDriverBiDiPort, - ] = await Promise.all([getPort(), getPort(), getPort(), getPort()]) + ] = await Promise.all([getPort(), getPort(), getPort()]) defaultLaunchOptions.preferences['devtools.debugger.remote-port'] = foxdriverPort defaultLaunchOptions.preferences['marionette.port'] = marionettePort // NOTE: we get the BiDi port and set it inside of geckodriver, but BiDi is not currently enabled (see remote.active-protocols above). // this is so the BiDi websocket port does not get set to 0, which is the default for the geckodriver package. - debug('available ports: %o', { foxdriverPort, marionettePort, geckoDriverPort, webDriverBiDiPort }) + debug('available ports: %o', { foxdriverPort, marionettePort, webDriverBiDiPort }) const [ cacheDir, @@ -524,15 +527,16 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc debug('launching geckodriver with browser envs %o', BROWSER_ENVS) - // create the geckodriver process, which we will use WebDriver Classic to open the browser - const geckoDriverInstance = await GeckoDriver.create({ + debug('launch in firefox', { url, args: launchOptions.args }) + + const geckoDriverOptions: GeckoDriverOptions = { host: '127.0.0.1', - port: geckoDriverPort, + // geckodriver port is assigned under the hood by @wdio/utils + // @see https://github.com/webdriverio/webdriverio/blob/v9.1.1/packages/wdio-utils/src/node/startWebDriver.ts#L65 marionetteHost: '127.0.0.1', marionettePort, - webdriverBidiPort: webDriverBiDiPort, - profilePath: profile.path(), - binaryPath: browser.path, + websocketPort: webDriverBiDiPort, + profileRoot: profile.path(), // To pass env variables into the firefox process, we CANNOT do it through capabilities when starting the browser. // Since geckodriver spawns the firefox process, we can pass the env variables directly to geckodriver, which in turn will // pass them to the firefox process @@ -544,15 +548,16 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc ...process.env, }, }, - }) - - const wdcInstance = new WebDriverClassic('127.0.0.1', geckoDriverPort) - - debug('launch in firefox', { url, args: launchOptions.args }) + jsdebugger: Debug.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE) || false, + log: Debug.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE) ? 'debug' : 'error', + logNoTruncate: Debug.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE), + } - const capabilitiesToSend = { + const newSessionCapabilities: RemoteConfig = { + logLevel: Debug.enabled(WEBDRIVER_DEBUG_NAMESPACE_VERBOSE) ? 'info' : 'silent', capabilities: { alwaysMatch: { + browserName: 'firefox', acceptInsecureCerts: true, // @see https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions 'moz:firefoxOptions': { @@ -562,27 +567,58 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc }, // @see https://firefox-source-docs.mozilla.org/testing/geckodriver/Capabilities.html#moz-debuggeraddress // we specify the debugger address option for Webdriver, which will return us the CDP address when the capability is returned. + // @ts-expect-error 'moz:debuggerAddress': true, + // @see https://webdriver.io/docs/capabilities/#wdiogeckodriveroptions + 'wdio:geckodriverOptions': geckoDriverOptions, }, + firstMatch: [], }, } + // @ts-expect-error + let browserInstanceWrapper: BrowserInstance = new EventEmitter() + + browserInstanceWrapper.kill = () => undefined try { - debugVerbose(`creating session with capabilities %s`, JSON.stringify(capabilitiesToSend.capabilities)) + debugVerbose(`creating session with capabilities %s`, JSON.stringify(newSessionCapabilities.capabilities)) + + const WD = WebDriver.getWebDriverPackage() // this command starts the webdriver session and actually opens the browser - const { capabilities } = await wdcInstance.createSession(capabilitiesToSend) + // to debug geckodriver, set the DEBUG=cypress-verbose:server:browsers:geckodriver (debugs a third-party patched package geckodriver) + // @see ./WEB_DRIVER.md + const webdriverClient = await WD.newSession(newSessionCapabilities) - debugVerbose(`received capabilities %o`, capabilities) + debugVerbose(`received capabilities %o`, webdriverClient.capabilities) - const cdpPort = parseInt(new URL(`ws://${capabilities['moz:debuggerAddress']}`).port) + const cdpPort = parseInt(new URL(`ws://${webdriverClient.capabilities['moz:debuggerAddress']}`).port) debug(`CDP running on port ${cdpPort}`) - const browserPID = capabilities['moz:processID'] + const browserPID: number = webdriverClient.capabilities['moz:processID'] debug(`firefox running on pid: ${browserPID}`) + const driverPID: number = webdriverClient.capabilities['wdio:driverPID'] as number + + debug(`webdriver running on pid: ${driverPID}`) + + // now that we have the driverPID and browser PID + browserInstanceWrapper.kill = (...args) => { + // Do nothing on failure here since we're shutting down anyway + clearInstanceState({ gracefulShutdown: true }) + + debug('closing firefox') + + const browserReturnStatus = process.kill(browserPID) + + debug('closing geckodriver and webdriver') + const driverReturnStatus = process.kill(driverPID) + + return browserReturnStatus || driverReturnStatus + } + // makes it so get getRemoteDebuggingPort() is calculated correctly process.env.CYPRESS_REMOTE_DEBUGGING_PORT = cdpPort.toString() @@ -591,37 +627,21 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc // as firefox will create the profile under the profile root that we cannot control and we cannot consistently provide // a base 64 encoded profile. if (!browser.isHeadless && (!launchOptions.args.includes('-width') || !launchOptions.args.includes('-height'))) { - await wdcInstance.maximizeWindow() + await webdriverClient.maximizeWindow() } // install the browser extensions - await Promise.all(_.map(launchOptions.extensions, (path) => { + await Promise.all(_.map(launchOptions.extensions, async (path) => { debug(`installing extension at path: ${path}`) + const id = await webdriverClient.installAddOn(path, true) + + debug(`extension with id ${id} installed!`) - return wdcInstance!.installAddOn({ - path, - temporary: true, - }) + return })) debug('setting up firefox utils') - browserCriClient = await firefoxUtil.setup({ automation, url, foxdriverPort, webDriverClassic: wdcInstance, remotePort: cdpPort, onError: options.onError }) - - // monkey-patch the .kill method to that the CDP connection is closed - const originalGeckoDriverKill = geckoDriverInstance.kill - - geckoDriverInstance.kill = (...args) => { - // Do nothing on failure here since we're shutting down anyway - clearInstanceState({ gracefulShutdown: true }) - - debug('closing firefox') - - process.kill(browserPID) - - debug('closing geckodriver') - - return originalGeckoDriverKill.apply(geckoDriverInstance, args) - } + browserCriClient = await firefoxUtil.setup({ automation, url, foxdriverPort, webdriverClient, remotePort: cdpPort, onError: options.onError }) await utils.executeAfterBrowserLaunch(browser, { webSocketDebuggerUrl: browserCriClient.getWebSocketDebuggerUrl(), @@ -630,7 +650,7 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc errors.throwErr('FIREFOX_COULD_NOT_CONNECT', err) } - return geckoDriverInstance + return browserInstanceWrapper } export async function closeExtraTargets () { diff --git a/packages/server/lib/browsers/geckodriver/README.md b/packages/server/lib/browsers/firefox_automation.md similarity index 55% rename from packages/server/lib/browsers/geckodriver/README.md rename to packages/server/lib/browsers/firefox_automation.md index fb635abd7203..342848c01989 100644 --- a/packages/server/lib/browsers/geckodriver/README.md +++ b/packages/server/lib/browsers/firefox_automation.md @@ -1,35 +1,39 @@ -# GeckoDriver +# Firefox Automation -## Purpose +## GeckoDriver / WebDriver Classic -Cypress uses [GeckoDriver](https://firefox-source-docs.mozilla.org/testing/geckodriver/index.html) to drive [classic WebDriver](https://w3c.github.io/webdriver.) methods, as well as interface with Firefox's [Marionette Protocol](https://firefox-source-docs.mozilla.org/testing/marionette/Intro.html). This is necessary to automate the Firefox browser in the following cases: +### Purpose -* Navigating to the current/next spec URL via [WebDriver Classic](https://w3c.github.io/webdriver.). +Cypress uses [GeckoDriver](https://firefox-source-docs.mozilla.org/testing/geckodriver/index.html) to drive [classic WebDriver](https://w3c.github.io/webdriver) methods, as well as interface with Firefox's [Marionette Protocol](https://firefox-source-docs.mozilla.org/testing/marionette/Intro.html). This is necessary to automate the Firefox browser in the following cases: + +* Navigating to the current/next spec URL via [WebDriver Classic](https://w3c.github.io/webdriver). * Installing the [Cypress web extension](https://github.com/cypress-io/cypress/tree/develop/packages/extension) via the [Marionette Protocol](https://firefox-source-docs.mozilla.org/testing/marionette/Intro.html), which is critical to automating Firefox. +The [WebDriver](https://w3c.github.io/webdriver) methods used come from the [webdriver](https://github.com/webdriverio/webdriverio/tree/main/packages/webdriver) package to drive WebDriver (and in the future, WebDriver BiDi), which also starts the [geckodriver](https://github.com/webdriverio-community/node-geckodriver#readme) for us using the [`wdio:geckodriverOptions`](https://webdriver.io/docs/capabilities/#wdiogeckodriveroptions) capability. + Currently, [Chrome Devtools Protocol](https://chromedevtools.github.io/devtools-protocol/) automates most of our browser interactions with Firefox. However, [CDP will be removed towards the end of 2024](https://fxdx.dev/deprecating-cdp-support-in-firefox-embracing-the-future-with-webdriver-bidi/) now that [WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) is fully supported in Firefox 130 and up. [GeckoDriver](https://firefox-source-docs.mozilla.org/testing/geckodriver/index.html) will be the entry point in which Cypress implements [WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) for Firefox. -## Historical Context +### Historical Context Previously, Cypress was using an older package called the [marionette-client](https://github.com/cypress-io/marionette-client), which is near identical to the [mozilla b2g marionette client](https://github.com/mozilla-b2g/gaia/tree/master/tests/jsmarionette/client/marionette-client/lib/marionette). The b2g client hasn't had active development since 2014 and there have been changes to Marionette's server implementation since then. This means the [marionette-client](https://github.com/cypress-io/marionette-client) could break at any time, hence why we have migrated away from it. See [Cypress' migration to WebDriver BiDi within Firefox](https://bugzilla.mozilla.org/show_bug.cgi?id=1604723) bugzilla ticket for more details. -## Implementation +### Implementation To consume [`GeckoDriver`](https://firefox-source-docs.mozilla.org/testing/geckodriver/index.html), Cypress installs the [`geckodriver`](https://github.com/webdriverio-community/node-geckodriver#readme) package, a lightweight wrapper around the [geckodriver binary](https://github.com/mozilla/geckodriver), to connect to the Firefox browser. Once connected, `GeckoDriver` is able to send `WebDriver` commands, as well as `Marionette` commands, to the Firefox browser. It is also capable of creating a `WebDriver BiDi` session to send `WebDriver BiDi` commands and receive `WebDriver BiDi` events. -It is worth noting that Cypress patches the [`geckodriver`](https://github.com/webdriverio-community/node-geckodriver#readme) package for a few reasons: -* To coincide with our debug logs in order to not print extraneous messages to the console that could disrupt end user experience as well as impact our system tests. +It is worth noting that Cypress patches the [`geckodriver`](https://github.com/webdriverio-community/node-geckodriver#readme) and [`webdriver`](https://github.com/webdriverio/webdriverio/tree/main/packages/webdriver) packages for a few reasons: +* To coincide with our debug logs in order to not print extraneous messages to the console that could disrupt end user experience as well as impact our system tests. These can be turned on by setting the `DEBUG` variable to `cypress-verbose:server:browsers:geckodriver` or `cypress-verbose:server:browsers:webdriver` depending on what needs to be debugged * Patch top-level awaits to correctly build the app. -* Pass process spawning arguments to the geckodriver process (which is a child process of the main process) in order to set `MOZ_` prefixed environment variables in the browser. These cannot be set through the [env capability](https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions#env_object) and must be done through `geckodriver` as `geckodriver` spawns the `firefox` process. Please see [this comment](https://bugzilla.mozilla.org/show_bug.cgi?id=1604723#c20) for more details. -Currently, since the use of WebDriver Classic is so miniscule, the methods are implemented using direct fetch calls inside the [WebDriver Classic Class](../webdriver-classic/index.ts). It's important to note that, unlike Chrome, Firefox is launched via the WebDriver [newSession command](https://w3c.github.io/webdriver.#new-session) As BiDi development occurs and to reduce maintenance cost, using an already implemented client like [`webdriver`](https://www.npmjs.com/package/webdriver) will be explored. +Currently, the use of WebDriver Classic is small. To prepare for the implementation of WebDriver BiDi and reduce the need for maintenance code, the methods are implemented via the [webdriver](https://github.com/webdriverio/webdriverio/tree/main/packages/webdriver) package. It's important to note that, unlike Chrome, Firefox is launched via the WebDriver [newSession command](https://w3c.github.io/webdriver#new-session) (via `webdriver` [package](https://github.com/webdriverio/webdriverio/tree/main/packages/webdriver#webdriver-example)). -Since we patch the [`geckodriver`](https://github.com/webdriverio-community/node-geckodriver#readme) package, we [`nohoist`](https://classic.yarnpkg.com/blog/2018/02/15/nohoist/) the dependency. This mostly works with sub-dependencies, but one of the dependencies, `pump@^3.0.0` (from `geckodriver` -> `tar-fs` -> `pump`) is missing from the binary. To workaround this, we install `pump` in `@packages/server` and `nohoist` the dependency so it is available in the binary as a production dependency. +Since we patch the [`geckodriver`](https://github.com/webdriverio-community/node-geckodriver#readme) and the related [`webdriver`](https://github.com/webdriverio/webdriverio/tree/main/packages) packages, we [`nohoist`](https://classic.yarnpkg.com/blog/2018/02/15/nohoist/) the dependencies. This mostly works with sub-dependencies, but one of the dependencies, `pump@^3.0.0` (from `geckodriver` -> `tar-fs` -> `pump`) is missing from the binary. To workaround this, we install `pump` in `@packages/server` and `nohoist` the dependency so it is available in the binary as a production dependency. ## Debugging -To help debug `geckodriver` and `firefox`, the `DEBUG=cypress-verbose:server:browsers:geckodriver` can be used when launching `cypress`. This will +To help debug `geckodriver` and `firefox`, the `DEBUG=cypress-verbose:server:browsers:geckodriver,cypress-verbose:server:browsers:webdriver` can be used when launching `cypress`. This will * Enable full `stdout` and `stderr` for `geckodriver` (including startup time) and the `firefox` process. The logs will **NOT** be truncated so they may get quite long. * Enables the debugger terminal, which will additionally print browser information to the debugger terminal process. + * enables `webdriver` debug logs for all commands and events. If you are having trouble running firefox, turning on this debug option can be quite useful. diff --git a/packages/server/lib/browsers/geckodriver/index.ts b/packages/server/lib/browsers/geckodriver/index.ts deleted file mode 100644 index 8120ddb70736..000000000000 --- a/packages/server/lib/browsers/geckodriver/index.ts +++ /dev/null @@ -1,122 +0,0 @@ -import Bluebird from 'bluebird' -import debugModule from 'debug' -import errors from '@packages/errors' -import type { ChildProcess } from 'child_process' - -const geckoDriverPackageName = 'geckodriver' -const GECKODRIVER_DEBUG_NAMESPACE = 'cypress:server:browsers:geckodriver' -const GECKODRIVER_DEBUG_NAMESPACE_VERBOSE = 'cypress-verbose:server:browsers:geckodriver' -const debug = debugModule(GECKODRIVER_DEBUG_NAMESPACE) -const debugVerbose = debugModule(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE) - -type SpawnOpt = { [key: string]: string | string[] | SpawnOpt } - -export type StartGeckoDriverArgs = { - host: string - port: number - marionetteHost: string - marionettePort: number - webdriverBidiPort: number - profilePath: string - binaryPath: string - spawnOpts?: SpawnOpt -} - -/** - * Class with static methods that serve as a wrapper around GeckoDriver - */ -export class GeckoDriver { - // We resolve this package in such a way that packherd can discover it, meaning we are re-declaring the types here to get typings support =( - // the only reason a static method is used here is so we can stub the class method more easily while under unit-test - private static getGeckoDriverPackage: () => { - start: (args: { - allowHosts?: string[] - allowOrigins?: string[] - binary?: string - connectExisting?: boolean - host?: string - jsdebugger?: boolean - log?: 'fatal' | 'error' | 'warn' | 'info' | 'config' | 'debug' | 'trace' - logNoTruncate?: boolean - marionetteHost?: string - marionettePort?: number - port?: number - websocketPort?: number - profileRoot?: string - geckoDriverVersion?: string - customGeckoDriverPath?: string - cacheDir?: string - spawnOpts: SpawnOpt - }) => Promise - download: (geckodriverVersion?: string, cacheDir?: string) => Promise - } = () => { - /** - * NOTE: geckodriver is an ESM package and does not play well with mksnapshot. - * Requiring the package in this way, dynamically, will - * make it undiscoverable by mksnapshot - */ - return require(require.resolve(geckoDriverPackageName, { paths: [__dirname] })) - } - - /** - * creates an instance of the GeckoDriver server. This is needed to start WebDriver - * @param {StartGeckoDriverArgs} opts - arguments needed to start GeckoDriver - * @returns {ChildProcess} - the child process in which the geckodriver is running - */ - static async create (opts: StartGeckoDriverArgs, timeout: number = 5000): Promise { - debug('no geckodriver instance exists. starting geckodriver...') - - let geckoDriverChildProcess: ChildProcess | null = null - - try { - const { start: startGeckoDriver } = GeckoDriver.getGeckoDriverPackage() - - geckoDriverChildProcess = await startGeckoDriver({ - host: opts.host, - port: opts.port, - marionetteHost: opts.marionetteHost, - marionettePort: opts.marionettePort, - websocketPort: opts.webdriverBidiPort, - profileRoot: opts.profilePath, - binary: opts.binaryPath, - jsdebugger: debugModule.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE) || false, - log: debugModule.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE) ? 'debug' : 'error', - logNoTruncate: debugModule.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE), - spawnOpts: opts.spawnOpts || {}, - }) - - // using a require statement to make this easier to test with mocha/mockery - const waitPort = require('wait-port') - - await Bluebird.resolve(waitPort({ - port: opts.port, - // add 1 second to the timeout so the timeout throws first if the limit is reached - timeout: timeout + 1000, - output: debugModule.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE) ? 'dots' : 'silent', - })).timeout(timeout) - - debug('geckodriver started!') - - // For whatever reason, we NEED to bind to stderr/stdout in order - // for the geckodriver process not to hang, even though the event effectively - // isn't doing anything without debug logs enabled. - geckoDriverChildProcess.stdout?.on('data', (buf) => { - debugVerbose('firefox stdout: %s', String(buf).trim()) - }) - - geckoDriverChildProcess.stderr?.on('data', (buf) => { - debugVerbose('firefox stderr: %s', String(buf).trim()) - }) - - geckoDriverChildProcess.on('exit', (code, signal) => { - debugVerbose('firefox exited: %o', { code, signal }) - }) - - return geckoDriverChildProcess - } catch (err) { - geckoDriverChildProcess?.kill() - debug(`geckodriver failed to start from 'geckodriver:start' for reason: ${err}`) - throw errors.get('FIREFOX_GECKODRIVER_FAILURE', 'geckodriver:start', err) - } - } -} diff --git a/packages/server/lib/browsers/webdriver-classic/index.ts b/packages/server/lib/browsers/webdriver-classic/index.ts deleted file mode 100644 index 81eb62e06b87..000000000000 --- a/packages/server/lib/browsers/webdriver-classic/index.ts +++ /dev/null @@ -1,263 +0,0 @@ -import debugModule from 'debug' -// using cross fetch to make unit testing easier to mock -import crossFetch from 'cross-fetch' - -const debug = debugModule('cypress:server:browsers:webdriver') - -type InstallAddOnArgs = { - path: string - temporary: boolean -} - -namespace WebDriver { - export namespace Session { - export type NewResult = { - capabilities: { - acceptInsecureCerts: boolean - browserName: string - browserVersion: string - platformName: string - pageLoadStrategy: 'normal' - strictFileInteractability: boolean - timeouts: { - implicit: number - pageLoad: number - script: number - } - 'moz:accessibilityChecks': boolean - 'moz:buildID': string - 'moz:geckodriverVersion': string - 'moz:debuggerAddress': string - 'moz:headless': boolean - 'moz:platformVersion': string - 'moz:processID': number - 'moz:profile': string - 'moz:shutdownTimeout': number - 'moz:webdriverClick': boolean - 'moz:windowless': boolean - unhandledPromptBehavior: string - userAgent: string - sessionId: string - } - } - } -} - -export class WebDriverClassic { - #host: string - #port: number - private sessionId: string = '' - - constructor (host: string, port: number) { - this.#host = host - this.#port = port - } - - /** - * Creates a new WebDriver Session through GeckoDriver. Capabilities are predetermined - * @see https://w3c.github.io/webdriver.#new-session - * @returns {Promise} - the results of the Webdriver Session (enabled through remote.active-protocols) - */ - async createSession (args: { - capabilities: {[key: string]: any} - }): Promise { - const getSessionUrl = `http://${this.#host}:${this.#port}/session` - - const body = { - capabilities: args.capabilities, - } - - try { - const createSessionResp = await crossFetch(getSessionUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(body), - }) - - if (!createSessionResp.ok) { - const error = new Error(`${createSessionResp.status}: ${createSessionResp.statusText}.`) - - try { - const resp = await createSessionResp.json() - - error.message = `${error.message } ${resp.value.error}. ${resp.value.message}.` - } finally { - // if for some reason we can't parse the response, continue to throw with some information. - throw error - } - } - - const createSessionRespBody = await createSessionResp.json() - - this.sessionId = createSessionRespBody.value.sessionId - - return createSessionRespBody.value - } catch (e) { - debug(`unable to create new Webdriver session: ${e}`) - throw e - } - } - - /** - * Gets available windows handles in the browser. The order in which the window handles are returned is arbitrary. - * @see https://w3c.github.io/webdriver.#get-window-handles - * - * @returns {Promise} All the available top-level contexts/handles - */ - async getWindowHandles (): Promise { - const getWindowHandles = `http://${this.#host}:${this.#port}/session/${this.sessionId}/window/handles` - - try { - const getWindowHandlesResp = await crossFetch(getWindowHandles) - - if (!getWindowHandlesResp.ok) { - throw new Error(`${getWindowHandlesResp.status}: ${getWindowHandlesResp.statusText}`) - } - - const getWindowHandlesRespBody = await getWindowHandlesResp.json() - - return getWindowHandlesRespBody.value - } catch (e) { - debug(`unable to get classic webdriver window handles: ${e}`) - throw e - } - } - - /** - * Switching windows will select the session's current top-level browsing context as the target for all subsequent commands. - * In a tabbed browser, this will typically make the tab containing the browsing context the selected tab. - * @see https://w3c.github.io/webdriver.#dfn-switch-to-window - * - * @param {string} handle - the context ID of the window handle - * @returns {Promise} - */ - async switchToWindow (handle: string): Promise { - const switchToWindowUrl = `http://${this.#host}:${this.#port}/session/${this.sessionId}/window` - - const body = { - handle, - } - - try { - const switchToWindowResp = await crossFetch(switchToWindowUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(body), - }) - - if (!switchToWindowResp.ok) { - throw new Error(`${switchToWindowResp.status}: ${switchToWindowResp.statusText}`) - } - - const switchToWindowRespBody = await switchToWindowResp.json() - - return switchToWindowRespBody.value - } catch (e) { - debug(`unable to switch to window via classic webdriver : ${e}`) - throw e - } - } - - /** - * maximizes the current window - * @see https://w3c.github.io/webdriver.#maximize-window - * - * @returns {Promise} - */ - async maximizeWindow (): Promise { - const maximizeWindowUrl = `http://${this.#host}:${this.#port}/session/${this.sessionId}/window/maximize` - - try { - const maximizeWindowResp = await crossFetch(maximizeWindowUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({}), - }) - - if (!maximizeWindowResp.ok) { - throw new Error(`${maximizeWindowResp.status}: ${maximizeWindowResp.statusText}`) - } - - const maximizeWindowRespBody = await maximizeWindowResp.json() - - return maximizeWindowRespBody.value - } catch (e) { - debug(`unable to maximize window via classic webdriver : ${e}`) - throw e - } - } - - /** - * causes the user agent to navigate the session's current top-level browsing context to a new location. - * @see https://w3c.github.io/webdriver.#navigate-to - * - * @param url - the url of where the context handle is navigating to - * @returns {Promise} - */ - async navigate (url: string): Promise { - const navigateUrl = `http://${this.#host}:${this.#port}/session/${this.sessionId}/url` - - const body = { - url, - } - - try { - const navigateResp = await crossFetch(navigateUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(body), - }) - - if (!navigateResp.ok) { - throw new Error(`${navigateResp.status}: ${navigateResp.statusText}`) - } - - const navigateRespBody = await navigateResp.json() - - return navigateRespBody.value - } catch (e) { - debug(`unable to navigate via classic webdriver : ${e}`) - throw e - } - } - - /** - * Installs a web extension on the given WebDriver session - * @see https://searchfox.org/mozilla-central/rev/cc01f11adfacca9cd44a75fd140d2fdd8f9a48d4/testing/geckodriver/src/command.rs#33-36 - * @param {InstallAddOnArgs} opts - options needed to install a web extension. - */ - async installAddOn (opts: InstallAddOnArgs) { - const body = { - path: opts.path, - temporary: opts.temporary, - } - - // If the webdriver session is created, we can now install our extension through geckodriver - const url = `http://${this.#host}:${this.#port}/session/${this.sessionId}/moz/addon/install` - - try { - const resp = await crossFetch(url, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(body), - }) - - if (!resp.ok) { - throw new Error(`${resp.status}: ${resp.statusText}`) - } - } catch (e) { - debug(`unable to install extension: ${e}`) - throw e - } - } -} diff --git a/packages/server/lib/browsers/webdriver/index.ts b/packages/server/lib/browsers/webdriver/index.ts new file mode 100644 index 000000000000..19648325c7cf --- /dev/null +++ b/packages/server/lib/browsers/webdriver/index.ts @@ -0,0 +1,38 @@ +import type { SpawnOptionsWithoutStdio, SpawnOptionsWithStdioTuple, StdioNull, StdioPipe } from 'child_process' +import type WebDriverPackage from 'webdriver' + +const webDriverPackageName = 'webdriver' + +type StdioOption = StdioNull | StdioPipe + +export type GeckoDriverOptions = { + allowHosts?: string[] + allowOrigins?: string[] + binary?: string + connectExisting?: boolean + host?: string + jsdebugger?: boolean + log?: 'fatal' | 'error' | 'warn' | 'info' | 'config' | 'debug' | 'trace' + logNoTruncate?: boolean + marionetteHost?: string + marionettePort?: number + port?: number + websocketPort?: number + profileRoot?: string + geckoDriverVersion?: string + customGeckoDriverPath?: string + cacheDir?: string + spawnOpts: SpawnOptionsWithoutStdio | SpawnOptionsWithStdioTuple +} + +export class WebDriver { + // We resolve this package in such a way to packherd can discover it. + static getWebDriverPackage: () => typeof WebDriverPackage = () => { + /** + * NOTE: webdriver is an ESM package and does not play well with mksnapshot. + * Requiring the package in this way, dynamically, will + * make it undiscoverable by mksnapshot + */ + return require(require.resolve(webDriverPackageName, { paths: [__dirname] })) + } +} diff --git a/packages/server/package.json b/packages/server/package.json index 6374ba01e5f5..486f2dddd304 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -71,7 +71,7 @@ "firefox-profile": "4.6.0", "fluent-ffmpeg": "2.1.2", "fs-extra": "9.1.0", - "geckodriver": "4.4.2", + "geckodriver": "4.5.0", "get-port": "5.1.1", "getos": "3.2.1", "glob": "7.1.3", @@ -131,6 +131,7 @@ "url-parse": "1.5.10", "uuid": "8.3.2", "wait-port": "1.1.0", + "webdriver": "9.0.0", "webpack-virtual-modules": "0.5.0", "widest-line": "3.1.0" }, @@ -220,7 +221,8 @@ "geckodriver", "http-proxy", "pump", - "tsconfig-paths" + "tsconfig-paths", + "webdriver" ] }, "optionalDependencies": { diff --git a/packages/server/patches/@wdio+protocols+9.0.0.patch b/packages/server/patches/@wdio+protocols+9.0.0.patch new file mode 100644 index 000000000000..840928bb1716 --- /dev/null +++ b/packages/server/patches/@wdio+protocols+9.0.0.patch @@ -0,0 +1,79 @@ +diff --git a/node_modules/@wdio/protocols/README.md b/node_modules/@wdio/protocols/README.md +deleted file mode 100644 +index eea42bf..0000000 +--- a/node_modules/@wdio/protocols/README.md ++++ /dev/null +@@ -1,55 +0,0 @@ +-WebdriverIO Protocol Helper +-=========================== +- +-This package stores the definition for various automation protocols such as [WebDriver](https://w3c.github.io/webdriver/) or vendor specific protocol extensions like for [SauceLabs](https://saucelabs.com/). Unless you are interested in generating a WebDriver client there should be no reason why you should need this package. This package holds the definition of the following protocols: +- +-- [WebDriver](https://w3c.github.io/webdriver/) +-- [JSON Wire Protocol](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol) +-- [Appium](http://appium.io/) +-- [Mobile JSON Wire Protocol](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md) +-- [Sauce Labs](https://saucelabs.com/) +-- Chrome (WebDriver extension when running Chromedriver) +-- Selenium (when running Selenium Standalone Server) +- +-## Install +- +-To install the package, run: +- +-```sh +-npm install @wdio/protocols +-``` +- +-## Usage +- +-You can get data by importing the package as follows: +- +-```js +-import { WebDriverProtocol, MJsonWProtocol, AppiumProtocol, ChromiumProtocol, SauceLabsProtocol, SeleniumProtocol } from '@wdio/protocols' +- +-/** +- * get description of session command +- */ +-console.log(WebDriverProtocol['/session'].POST.description) +-``` +- +-## TypeScript Interfaces +- +-The package exposes TypeScript interfaces for all protocols. You can use them for your own project as follows: +- +-```ts +-import type { WebDriverCommands } from '@wdio/protocol' +- +-import { WebDriverCommands, WebDriverCommandsAsync } from './src' +- +-const browser = {} as WebDriverCommands +-browser.sendAlertText(true) +-// fails with "Argument of type 'boolean' is not assignable to parameter of type 'string'.ts(2345)" +- +-const asyncBrowser = {} as WebDriverCommandsAsync +-const a = await asyncBrowser.getTitle() +-type foo = typeof a // string +-``` +- +----- +- +-For more information on WebdriverIO see the [homepage](https://webdriver.io). +diff --git a/node_modules/@wdio/protocols/build/index.js b/node_modules/@wdio/protocols/build/index.js +index 05e55cc..9ea546e 100644 +--- a/node_modules/@wdio/protocols/build/index.js ++++ b/node_modules/@wdio/protocols/build/index.js +@@ -5165,9 +5165,11 @@ var gecko_default = { + ], + parameters: [ + { +- name: "addon", ++ // cypress uses 'path' over 'addon' to avoid zipping the extension, ++ // which is easier for cypress to encorporate and doesn't break users ++ name: "path", + type: "string", +- description: "base64 string of the add on file", ++ description: "string of the add on file", + required: true + }, + { diff --git a/packages/server/patches/@wdio+utils+9.0.0.patch b/packages/server/patches/@wdio+utils+9.0.0.patch new file mode 100644 index 000000000000..9e1f8eac9b56 --- /dev/null +++ b/packages/server/patches/@wdio+utils+9.0.0.patch @@ -0,0 +1,31 @@ +diff --git a/node_modules/@wdio/utils/README.md b/node_modules/@wdio/utils/README.md +deleted file mode 100644 +index 3e8048a..0000000 +--- a/node_modules/@wdio/utils/README.md ++++ /dev/null +@@ -1,4 +0,0 @@ +-WDIO Repl +-========= +- +-> A WDIO helper utility to provide a repl interface WebdriverIO +diff --git a/node_modules/@wdio/utils/build/index.js b/node_modules/@wdio/utils/build/index.js +index 1540cb6..07bd02e 100644 +--- a/node_modules/@wdio/utils/build/index.js ++++ b/node_modules/@wdio/utils/build/index.js +@@ -571,6 +571,7 @@ import cp2 from "node:child_process"; + import getPort from "get-port"; + import waitPort from "wait-port"; + import logger3 from "@wdio/logger"; ++import debugModule from 'debug' + import split2 from "split2"; + import { deepmerge } from "deepmerge-ts"; + import { start as startSafaridriver } from "safaridriver"; +@@ -681,6 +682,8 @@ var init_startWebDriver = __esm({ + init_utils(); + init_constants(); + log2 = logger3("@wdio/utils"); ++ // wrap in cypress debugger statement to avoid extraneous messages to the console ++ log2.setLevel(debugModule.enabled('cypress-verbose:server:browsers:webdriver') ? 'info' : 'silent') + DRIVER_WAIT_TIMEOUT = 10 * 1e3; + } + }); diff --git a/packages/server/patches/geckodriver+4.4.2.patch b/packages/server/patches/geckodriver+4.5.0.patch similarity index 77% rename from packages/server/patches/geckodriver+4.4.2.patch rename to packages/server/patches/geckodriver+4.5.0.patch index 18628d957f8d..77ea1dcef764 100644 --- a/packages/server/patches/geckodriver+4.4.2.patch +++ b/packages/server/patches/geckodriver+4.5.0.patch @@ -1,9 +1,9 @@ diff --git a/node_modules/geckodriver/README.md b/node_modules/geckodriver/README.md deleted file mode 100644 -index 8634875..0000000 +index 95e3ef0..0000000 --- a/node_modules/geckodriver/README.md +++ /dev/null -@@ -1,230 +0,0 @@ +@@ -1,239 +0,0 @@ -Geckodriver [![CI](https://github.com/webdriverio-community/node-geckodriver/actions/workflows/ci.yml/badge.svg)](https://github.com/webdriverio-community/node-geckodriver/actions/workflows/ci.yml) [![Audit](https://github.com/webdriverio-community/node-geckodriver/actions/workflows/audit.yml/badge.svg)](https://github.com/webdriverio-community/node-geckodriver/actions/workflows/audit.yml) -========== - @@ -223,6 +223,15 @@ index 8634875..0000000 -Type: `string`
-Default: `process.env.GECKODRIVER_CACHE_DIR || os.tmpdir()` - +-### `spawnOpts` +-Options to pass into the geckodriver process. This can be useful if needing +-Firefox to spawn with `MOZ_` prefix variables, such as `MOZ_HEADLESS_WIDTH`. +-See https://nodejs.org/api/child_process.html#child_processspawncommand-args-options for +-all options. +- +-Type: `SpawnOptionsWithoutStdio | SpawnOptionsWithStdioTuple`
+-Default: `undefined` +- -# Other Browser Driver - -If you also look for other browser driver NPM wrappers, you can find them here: @@ -235,69 +244,27 @@ index 8634875..0000000 - -For more information on WebdriverIO see the [homepage](https://webdriver.io). diff --git a/node_modules/geckodriver/dist/index.js b/node_modules/geckodriver/dist/index.js -index 2367e0b..18be0e1 100644 +index 2edc6d2..8d6132d 100644 --- a/node_modules/geckodriver/dist/index.js +++ b/node_modules/geckodriver/dist/index.js -@@ -1,11 +1,11 @@ +@@ -1,10 +1,13 @@ import cp from 'node:child_process'; --import logger from '@wdio/logger'; -+import debugModule from 'debug'; + import logger from '@wdio/logger'; ++import debugModule from 'debug' import { download as downloadDriver } from './install.js'; import { hasAccess, parseParams } from './utils.js'; import { DEFAULT_HOSTNAME } from './constants.js'; --const log = logger('geckodriver'); -+const debug = debugModule('cypress-verbose:server:browsers:geckodriver'); + const log = logger('geckodriver'); export async function start(params) { -- const { cacheDir, customGeckoDriverPath, ...startArgs } = params; -+ const { cacheDir, customGeckoDriverPath, spawnOpts, ...startArgs } = params; ++ // wrap in cypress debugger statement to avoid extraneous messages to the console ++ log.setLevel(debugModule.enabled('cypress-verbose:server:browsers:geckodriver') ? 'info' : 'silent') + const { cacheDir, customGeckoDriverPath, spawnOpts, ...startArgs } = params; let geckoDriverPath = (customGeckoDriverPath || process.env.GECKODRIVER_PATH || - // deprecated -@@ -23,8 +23,8 @@ export async function start(params) { - // Otherwise all instances try to connect to the default port and fail - startArgs.websocketPort = startArgs.websocketPort ?? 0; - const args = parseParams(startArgs); -- log.info(`Starting Geckodriver at ${geckoDriverPath} with params: ${args.join(' ')}`); -- return cp.spawn(geckoDriverPath, args); -+ debug(`Starting Geckodriver at ${geckoDriverPath} with params: ${args.join(' ')}`); -+ return cp.spawn(geckoDriverPath, args, spawnOpts); - } - export const download = downloadDriver; - export * from './types.js'; diff --git a/node_modules/geckodriver/dist/install.js b/node_modules/geckodriver/dist/install.js -index c27c805..d230983 100644 +index c27c805..ac53518 100644 --- a/node_modules/geckodriver/dist/install.js +++ b/node_modules/geckodriver/dist/install.js -@@ -4,14 +4,14 @@ import util from 'node:util'; - import stream from 'node:stream'; - import fsp, { writeFile } from 'node:fs/promises'; - import zlib from 'node:zlib'; --import logger from '@wdio/logger'; -+import debugModule from 'debug'; - import tar from 'tar-fs'; - import { HttpsProxyAgent } from 'https-proxy-agent'; - import { HttpProxyAgent } from 'http-proxy-agent'; - import { BINARY_FILE, GECKODRIVER_CARGO_YAML } from './constants.js'; - import { hasAccess, getDownloadUrl, retryFetch } from './utils.js'; - import { BlobReader, BlobWriter, ZipReader } from '@zip.js/zip.js'; --const log = logger('geckodriver'); -+const debug = debugModule('cypress-verbose:server:browsers:geckodriver'); - const streamPipeline = util.promisify(stream.pipeline); - const fetchOpts = {}; - if (process.env.HTTPS_PROXY) { -@@ -36,10 +36,10 @@ export async function download(geckodriverVersion = process.env.GECKODRIVER_VERS - throw new Error(`Couldn't find version property in Cargo.toml file: ${JSON.stringify(toml)}`); - } - geckodriverVersion = version.split(' = ').pop().slice(1, -1); -- log.info(`Detected Geckodriver v${geckodriverVersion} to be latest`); -+ debug(`Detected Geckodriver v${geckodriverVersion} to be latest`); - } - const url = getDownloadUrl(geckodriverVersion); -- log.info(`Downloading Geckodriver from ${url}`); -+ debug(`Downloading Geckodriver from ${url}`); - const res = await retryFetch(url, fetchOpts); - if (res.status !== 200) { - throw new Error(`Failed to download binary (statusCode ${res.status}): ${res.statusText}`); @@ -70,6 +70,8 @@ async function downloadZip(res, cacheDir) { * download on install */ @@ -305,7 +272,7 @@ index c27c805..d230983 100644 - await download().then(() => log.info('Success!'), (err) => log.error(`Failed to install Geckodriver: ${err.stack}`)); + // removing the await here as packherd cannot bundle with a top-level await. + // This only has an impact if invoking from a CLI context, which cypress is not. -+ download().then(() => debug('Success!'), (err) => debug(`Failed to install Geckodriver: ${err.stack}`)); ++ download().then(() => log.info('Success!'), (err) => log.error(`Failed to install Geckodriver: ${err.stack}`)); } //# sourceMappingURL=install.js.map \ No newline at end of file diff --git a/packages/server/patches/webdriver+9.0.0.patch b/packages/server/patches/webdriver+9.0.0.patch new file mode 100644 index 000000000000..658561f221b4 --- /dev/null +++ b/packages/server/patches/webdriver+9.0.0.patch @@ -0,0 +1,199 @@ +diff --git a/node_modules/webdriver/README.md b/node_modules/webdriver/README.md +deleted file mode 100644 +index c3ed38d..0000000 +--- a/node_modules/webdriver/README.md ++++ /dev/null +@@ -1,170 +0,0 @@ +-WebDriver +-========= +- +-> A lightweight, non-opinionated implementation of the [WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) and [WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) specification including mobile commands supported by [Appium](http://appium.io/) +- +-There are [tons](https://github.com/christian-bromann/awesome-selenium#javascript) of Selenium and WebDriver binding implementations in the Node.js world. Every one of them has an opinionated API and recommended way to use it. This binding is the most non-opinionated you will find as it just represents the [WebDriver specification](https://w3c.github.io/webdriver/webdriver-spec.html) and doesn't come with any extra or higher-level abstraction. It is lightweight and comes with support for the [WebDriver specification](https://w3c.github.io/webdriver/webdriver-spec.html) and Appium's [Mobile JSONWire Protocol](https://github.com/appium/appium-base-driver/blob/master/docs/mjsonwp/protocol-methods.md). +- +-The package supports the following protocols: +- +-- [WebDriver](https://w3c.github.io/webdriver/) +-- [WebDriver Bidi](https://w3c.github.io/webdriver-bidi/) +-- [Appium](http://appium.io/) +-- [Chromium](http://chromedriver.chromium.org/) (additional Chromedriver specific commands) +-- [Selenium](https://www.selenium.dev/) (additional Selenium WebDriver specific commands) +-- [Sauce Labs](https://saucelabs.com/) (Sauce Labs specific WebDriver extensions) +-- [JSONWireProtocol](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol) (depcrecated) +-- [Mobile JSONWireProtocol](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md) (depcrecated) +- +-Commands are added to the client's protocol based on assumptions of provided capabilities. You can find more details about the commands by checking out the [`@wdio/protocols`](https://www.npmjs.com/package/@wdio/protocols) package. All commands come with TypeScript support. +- +-## Install +- +-To install this package from NPM run: +- +-```sh +-npm i webdriver +-``` +- +-## WebDriver Example +- +-The following example demonstrates a simple Google Search scenario: +- +-```js +-import WebDriver from 'webdriver'; +- +-const client = await WebDriver.newSession({ +- path: '/', +- capabilities: { browserName: 'firefox' } +-}) +- +-await client.navigateTo('https://www.google.com/ncr') +- +-const searchInput = await client.findElement('css selector', '#lst-ib') +-await client.elementSendKeys(searchInput['element-6066-11e4-a52e-4f735466cecf'], 'WebDriver') +- +-const searchBtn = await client.findElement('css selector', 'input[value="Google Search"]') +-await client.elementClick(searchBtn['element-6066-11e4-a52e-4f735466cecf']) +- +-console.log(await client.getTitle()) // outputs "WebDriver - Google Search" +- +-await client.deleteSession() +-``` +- +-## WebDriver Bidi Example +- +-To connect to the WebDriver Bidi protocol you have to send along a `webSocketUrl` flag to tell the browser driver to opt-in to the protocol: +- +-```js +-import WebDriver from 'webdriver' +- +-const browser = await WebDriver.newSession({ +- capabilities: { +- webSocketUrl: true, +- browserName: 'firefox' +- } +-}) +- +-await browser.sessionSubscribe({ events: ['log.entryAdded'] }) +- +-/** +- * returns: {"type":"console","method":"log","realm":null,"args":[{"type":"string","value":"Hello Bidi"}],"level":"info","text":"Hello Bidi","timestamp":1657282076037} +- */ +-browser.on('log.entryAdded', (entryAdded) => console.log('received %s', entryAdded)) +- +-await browser.executeScript('console.log("Hello Bidi")', []) +-await browser.deleteSession() +-``` +- +-# Configuration +- +-To create a WebDriver session call the `newSession` method on the `WebDriver` class and pass in your configurations: +- +-```js +-import WebDriver from 'webdriver' +-const client = await WebDriver.newSession(options) +-``` +- +-The following options are available: +- +-### capabilities +-Defines the [capabilities](https://w3c.github.io/webdriver/webdriver-spec.html#capabilities) you want to run in your WebDriver session. Note: by default, it will automatically set the `webSocketUrl` to establish a [WebDriver Bidi](https://w3c.github.io/webdriver-bidi/) session, if you don't want this, make sure to set `'wdio:enforceWebDriverClassic': true` in your capabilities. +- +-Type: `Object`
+-Required: `true` +- +-### logLevel +-Level of logging verbosity. +- +-Type: `String`
+-Default: *info*
+-Options: *trace* | *debug* | *info* | *warn* | *error* | *silent* +- +-### protocol +-Protocol to use when communicating with the Selenium standalone server (or driver). +- +-Type: `String`
+-Default: *http* +-Options: *http* | *https* +- +-### hostname +-Host of your WebDriver server. +- +-Type: `String`
+-Default: *localhost* +- +-### port +-Port your WebDriver server is on. +- +-Type: `Number`
+-Default: `undefined` +- +-### path +-Path to WebDriver endpoint or grid server. +- +-Type: `String`
+-Default: */* +- +-### queryParams +-Query parameters that are propagated to the driver server. +- +-Type: `Object` +-Default: `undefined` +- +-### connectionRetryTimeout +-Timeout for any WebDriver request to a driver or grid. +- +-Type: `Number`
+-Default: *120000* +- +-### connectionRetryCount +-Count of request retries to the Selenium server. +- +-Type: `Number`
+-Default: *3* +- +-### agent +- +-Allows you to use a custom` http`/`https`/`http2` [agent](https://www.npmjs.com/package/got#agent) to make requests. +- +-Type: `Object`
+-Default: +- +-```js +-{ +- http: new http.Agent({ keepAlive: true }), +- https: new https.Agent({ keepAlive: true }) +-} +-``` +- +-### transformRequest +-Function intercepting [HTTP request options](https://github.com/sindresorhus/got#options) before a WebDriver request is made to a driver. +- +-Type: `(RequestOptions) => RequestOptions`
+-Default: *none* +- +-### transformResponse +-Function intercepting HTTP response objects after a WebDriver response has arrived. +- +-Type: `(Response, RequestOptions) => Response`
+-Default: *none* +diff --git a/node_modules/webdriver/build/index.js b/node_modules/webdriver/build/index.js +index 3be438a..ecad188 100644 +--- a/node_modules/webdriver/build/index.js ++++ b/node_modules/webdriver/build/index.js +@@ -41,6 +41,10 @@ import { CAPABILITY_KEYS } from "@wdio/protocols"; + // src/bidi/core.ts + import logger from "@wdio/logger"; + ++// removing the await here as packherd cannot bundle with a top-level await. ++// Since we are using the package in a node context, we can just import 'ws' ++import socket_default from 'ws' ++ + // src/bidi/socket.ts + var BrowserSocket = class { + #callbacks = /* @__PURE__ */ new Set(); +@@ -78,7 +82,6 @@ var BrowserSocket = class { + this.#ws.close(); + } + }; +-var socket_default = globalThis.window ? BrowserSocket : (await import("ws")).default; + + // src/bidi/core.ts + var log = logger("webdriver"); diff --git a/packages/server/test/unit/browsers/firefox_spec.ts b/packages/server/test/unit/browsers/firefox_spec.ts index 54efd09c2f51..994a1c98cbef 100644 --- a/packages/server/test/unit/browsers/firefox_spec.ts +++ b/packages/server/test/unit/browsers/firefox_spec.ts @@ -1,6 +1,7 @@ require('../../spec_helper') import 'chai-as-promised' import { expect } from 'chai' +import debug from 'debug' import os from 'os' import sinon from 'sinon' import Foxdriver from '@benmalka/foxdriver' @@ -9,14 +10,13 @@ import firefoxUtil from '../../../lib/browsers/firefox-util' import { CdpAutomation } from '../../../lib/browsers/cdp_automation' import { BrowserCriClient } from '../../../lib/browsers/browser-cri-client' import { ICriClient } from '../../../lib/browsers/cri-client' -import { GeckoDriver } from '../../../lib/browsers/geckodriver' -import * as webDriverClassicImport from '../../../lib/browsers/webdriver-classic' +import { type Client as WebDriverClient, default as webdriver } from 'webdriver' +import { EventEmitter } from 'stream' const path = require('path') const _ = require('lodash') const mockfs = require('mock-fs') const FirefoxProfile = require('firefox-profile') -const launch = require('@packages/launcher/lib/browsers') const utils = require('../../../lib/browsers/utils') const plugins = require('../../../lib/plugins') const protocol = require('../../../lib/browsers/protocol') @@ -26,7 +26,8 @@ describe('lib/browsers/firefox', () => { const port = 3333 let foxdriver: any let foxdriverTab: any - let wdcInstance: sinon.SinonStubbedInstance + let wdInstance: sinon.SinonStubbedInstance + let browserCriClient: BrowserCriClient const stubFoxdriver = () => { foxdriverTab = { @@ -67,46 +68,26 @@ describe('lib/browsers/firefox', () => { sinon.stub(protocol, '_connectAsync').resolves(null) - this.browserInstance = { - // should be high enough to not kill any real PIDs - pid: Number.MAX_SAFE_INTEGER, - } - - sinon.stub(GeckoDriver, 'create').resolves(this.browserInstance) - - wdcInstance = sinon.createStubInstance(webDriverClassicImport.WebDriverClassic) - - wdcInstance.createSession.resolves({ + wdInstance = { + maximizeWindow: sinon.stub(), + installAddOn: sinon.stub(), + getWindowHandles: sinon.stub(), + switchToWindow: sinon.stub(), + navigateTo: sinon.stub(), capabilities: { 'moz:debuggerAddress': '127.0.0.1:12345', - acceptInsecureCerts: false, - browserName: '', - browserVersion: '', - platformName: '', - pageLoadStrategy: 'normal', - strictFileInteractability: false, - timeouts: { - implicit: 0, - pageLoad: 0, - script: 0, - }, - 'moz:accessibilityChecks': false, - 'moz:buildID': '', - 'moz:geckodriverVersion': '', - 'moz:headless': false, - 'moz:platformVersion': '', - 'moz:processID': 0, - 'moz:profile': '', - 'moz:shutdownTimeout': 0, - 'moz:webdriverClick': false, - 'moz:windowless': false, - unhandledPromptBehavior: '', - userAgent: '', - sessionId: '', + // @ts-expect-error + 'moz:processID': 1234, + 'wdio:driverPID': 5678, }, - }) + } - sinon.stub(webDriverClassicImport, 'WebDriverClassic').callsFake(() => wdcInstance) + wdInstance.maximizeWindow.resolves(null), + wdInstance.installAddOn.resolves(null), + wdInstance.switchToWindow.resolves(null), + wdInstance.navigateTo.resolves(null), + + sinon.stub(webdriver, 'newSession').resolves(wdInstance) stubFoxdriver() }) @@ -115,7 +96,7 @@ describe('lib/browsers/firefox', () => { beforeEach(function () { // majorVersion >= 86 indicates CDP support for Firefox, which provides // the CDP debugger URL for the after:browser:launch tests - this.browser = { name: 'firefox', channel: 'stable', majorVersion: 100 } + this.browser = { name: 'firefox', channel: 'stable', majorVersion: 100, path: '/path/to/binary' } this.automation = { use: sinon.stub().returns({}), } @@ -132,14 +113,13 @@ describe('lib/browsers/firefox', () => { sinon.stub(plugins, 'has') sinon.stub(plugins, 'execute') - sinon.stub(launch, 'launch').returns(this.browserInstance) sinon.stub(utils, 'writeExtension').resolves('/path/to/ext') sinon.stub(utils, 'getPort').resolves(1234) sinon.spy(FirefoxProfile.prototype, 'setPreference') sinon.spy(FirefoxProfile.prototype, 'updatePreferences') sinon.spy(FirefoxProfile.prototype, 'path') - const browserCriClient: BrowserCriClient = sinon.createStubInstance(BrowserCriClient) + browserCriClient = sinon.createStubInstance(BrowserCriClient) browserCriClient.attachToTargetUrl = sinon.stub().resolves({}) browserCriClient.getWebSocketDebuggerUrl = sinon.stub().returns('ws://debugger') @@ -156,131 +136,198 @@ describe('lib/browsers/firefox', () => { }) it('calls connectToNewSpec in firefoxUtil', async function () { - wdcInstance.getWindowHandles.resolves(['mock-context-id']) + wdInstance.getWindowHandles.resolves(['mock-context-id']) await firefox.open(this.browser, 'http://', this.options, this.automation) this.options.url = 'next-spec-url' await firefox.connectToNewSpec(this.browser, this.options, this.automation) expect(this.options.onInitializeNewBrowserTab).to.have.been.called - expect(wdcInstance.getWindowHandles).to.have.been.called - expect(wdcInstance.switchToWindow).to.have.been.calledWith('mock-context-id') + expect(wdInstance.getWindowHandles).to.have.been.called + expect(wdInstance.switchToWindow).to.have.been.calledWith('mock-context-id') // first time when connecting a new tab - expect(wdcInstance.navigate).to.have.been.calledWith('about:blank') + expect(wdInstance.navigateTo).to.have.been.calledWith('about:blank') // second time when navigating to the spec - expect(wdcInstance.navigate).to.have.been.calledWith('next-spec-url') + expect(wdInstance.navigateTo).to.have.been.calledWith('next-spec-url') }) }) - it('executes before:browser:launch if registered', function () { + it('executes before:browser:launch if registered', async function () { plugins.has.withArgs('before:browser:launch').returns(true) plugins.execute.resolves(null) - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(plugins.execute).to.be.calledWith('before:browser:launch') - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + expect(plugins.execute).to.be.calledWith('before:browser:launch') }) - it('does not execute before:browser:launch if not registered', function () { + it('does not execute before:browser:launch if not registered', async function () { plugins.has.withArgs('before:browser:launch').returns(false) - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(plugins.execute).not.to.be.calledWith('before:browser:launch') - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + + expect(plugins.execute).not.to.be.calledWith('before:browser:launch') }) - it('uses default preferences if before:browser:launch returns falsy value', function () { + it('uses default preferences if before:browser:launch returns falsy value', async function () { plugins.has.withArgs('before:browser:launch').returns(true) plugins.execute.resolves(null) - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.type', 1) - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.type', 1) }) - it('uses default preferences if before:browser:launch returns object with non-object preferences', function () { + it('uses default preferences if before:browser:launch returns object with non-object preferences', async function () { plugins.has.withArgs('before:browser:launch').returns(true) plugins.execute.resolves({ preferences: [], }) - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.type', 1) - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.type', 1) }) - it('sets preferences if returned by before:browser:launch', function () { + it('sets preferences if returned by before:browser:launch', async function () { plugins.has.withArgs('before:browser:launch').returns(true) plugins.execute.resolves({ preferences: { 'foo': 'bar' }, }) - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('foo', 'bar') + await firefox.open(this.browser, 'http://', this.options, this.automation) + + expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('foo', 'bar') + }) + + it('creates the WebDriver session and geckodriver instance through capabilities, installs the extension, and passes the correct port to CDP', async function () { + await firefox.open(this.browser, 'http://', this.options, this.automation) + expect(webdriver.newSession).to.have.been.calledWith({ + logLevel: 'silent', + capabilities: sinon.match({ + alwaysMatch: { + browserName: 'firefox', + acceptInsecureCerts: true, + // @see https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions + 'moz:firefoxOptions': { + binary: '/path/to/binary', + args: [ + '-new-instance', + '-start-debugger-server', + '-no-remote', + ...(os.platform() !== 'linux' ? ['-foreground'] : []), + ], + // only partially match the preferences object because it is so large + prefs: sinon.match({ + 'remote.active-protocols': 2, + 'remote.enabled': true, + }), + }, + 'moz:debuggerAddress': true, + 'wdio:geckodriverOptions': { + host: '127.0.0.1', + marionetteHost: '127.0.0.1', + marionettePort: sinon.match(Number), + websocketPort: sinon.match(Number), + profileRoot: '/path/to/appData/firefox-stable/interactive', + binaryPath: undefined, + spawnOpts: sinon.match({ + stdio: ['ignore', 'pipe', 'pipe'], + env: { + MOZ_REMOTE_SETTINGS_DEVTOOLS: '1', + MOZ_HEADLESS_WIDTH: '1280', + MOZ_HEADLESS_HEIGHT: '806', + }, + }), + jsdebugger: false, + log: 'error', + logNoTruncate: false, + + }, + }, + firstMatch: [], + }), }) + + expect(wdInstance.installAddOn).to.have.been.calledWith('/path/to/ext', true) + + expect(wdInstance.navigateTo).to.have.been.calledWith('http://') + + // make sure CDP gets the expected port + expect(BrowserCriClient.create).to.be.calledWith({ hosts: ['127.0.0.1', '::1'], port: 12345, browserName: 'Firefox', onAsynchronousError: undefined, onServiceWorkerClientEvent: undefined }) }) - it('creates the geckodriver, the creation of the WebDriver session, installs the extension, and passes the correct port to CDP', function () { - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(GeckoDriver.create).to.have.been.calledWith({ - host: '127.0.0.1', - port: sinon.match(Number), - marionetteHost: '127.0.0.1', - marionettePort: sinon.match(Number), - webdriverBidiPort: sinon.match(Number), - profilePath: '/path/to/appData/firefox-stable/interactive', - binaryPath: undefined, - spawnOpts: sinon.match({ - stdio: ['ignore', 'pipe', 'pipe'], - env: { - MOZ_REMOTE_SETTINGS_DEVTOOLS: '1', - MOZ_HEADLESS_WIDTH: '1280', - MOZ_HEADLESS_HEIGHT: '806', - }, - }), - }) + describe('debugging', () => { + afterEach(() => { + debug.disable() + }) - expect(wdcInstance.createSession).to.have.been.calledWith(sinon.match( - { - capabilities: { - alwaysMatch: { - acceptInsecureCerts: true, - 'moz:firefoxOptions': { - args: [ - '-new-instance', - '-start-debugger-server', - '-no-remote', - ...(os.platform() !== 'linux' ? ['-foreground'] : []), - ], - }, - 'moz:debuggerAddress': true, + it('sets additional arguments if "DEBUG=cypress-verbose:server:browsers:geckodriver" and "DEBUG=cypress-verbose:server:browsers:webdriver" is set', async function () { + debug.enable('cypress-verbose:server:browsers:geckodriver,cypress-verbose:server:browsers:webdriver') + + await firefox.open(this.browser, 'http://', this.options, this.automation) + + expect(webdriver.newSession).to.have.been.calledWith({ + logLevel: 'info', + capabilities: sinon.match({ + alwaysMatch: { + browserName: 'firefox', + acceptInsecureCerts: true, + // @see https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions + 'moz:firefoxOptions': { + binary: '/path/to/binary', + args: [ + '-new-instance', + '-start-debugger-server', + '-no-remote', + ...(os.platform() !== 'linux' ? ['-foreground'] : []), + ], + // only partially match the preferences object because it is so large + prefs: sinon.match({ + 'remote.active-protocols': 2, + 'remote.enabled': true, + }), + }, + 'moz:debuggerAddress': true, + 'wdio:geckodriverOptions': { + host: '127.0.0.1', + marionetteHost: '127.0.0.1', + marionettePort: sinon.match(Number), + websocketPort: sinon.match(Number), + profileRoot: '/path/to/appData/firefox-stable/interactive', + binaryPath: undefined, + spawnOpts: sinon.match({ + stdio: ['ignore', 'pipe', 'pipe'], + env: { + MOZ_REMOTE_SETTINGS_DEVTOOLS: '1', + MOZ_HEADLESS_WIDTH: '1280', + MOZ_HEADLESS_HEIGHT: '806', + }, + }), + jsdebugger: true, + log: 'debug', + logNoTruncate: true, }, }, - }, - )) + firstMatch: [], + }), + }) - expect(wdcInstance.installAddOn).to.have.been.calledWith(sinon.match({ - path: '/path/to/ext', - temporary: true, - })) + expect(wdInstance.installAddOn).to.have.been.calledWith('/path/to/ext', true) - expect(wdcInstance.navigate).to.have.been.calledWith('http://') + expect(wdInstance.navigateTo).to.have.been.calledWith('http://') // make sure CDP gets the expected port expect(BrowserCriClient.create).to.be.calledWith({ hosts: ['127.0.0.1', '::1'], port: 12345, browserName: 'Firefox', onAsynchronousError: undefined, onServiceWorkerClientEvent: undefined }) }) }) - it('does not maximize the browser if headless', function () { + it('does not maximize the browser if headless', async function () { this.browser.isHeadless = true - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(wdcInstance.maximizeWindow).not.to.have.been.called - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + expect(wdInstance.maximizeWindow).not.to.have.been.called }) - it('does not maximize the browser if "-width" or "-height" arg is set', function () { + it('does not maximize the browser if "-width" or "-height" arg is set', async function () { this.browser.isHeadless = false sinon.stub(utils, 'executeBeforeBrowserLaunch').resolves({ args: ['-width', '1280', '-height', '720'], @@ -288,34 +335,31 @@ describe('lib/browsers/firefox', () => { preferences: {}, }) - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(wdcInstance.maximizeWindow).not.to.have.been.called - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + expect(wdInstance.maximizeWindow).not.to.have.been.called }) - it('maximizes the browser if headed and no "-width" or "-height" arg is set', function () { + it('maximizes the browser if headed and no "-width" or "-height" arg is set', async function () { this.browser.isHeadless = false - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(wdcInstance.maximizeWindow).to.have.been.called - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + + expect(wdInstance.maximizeWindow).to.have.been.called }) - it('sets user-agent preference if specified', function () { + it('sets user-agent preference if specified', async function () { this.options.userAgent = 'User Agent' - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('general.useragent.override', 'User Agent') - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('general.useragent.override', 'User Agent') }) - it('writes extension', function () { - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(utils.writeExtension).to.be.calledWith(this.options.browser, this.options.isTextTerminal, this.options.proxyUrl, this.options.socketIoRoute) - }) + it('writes extension', async function () { + await firefox.open(this.browser, 'http://', this.options, this.automation) + expect(utils.writeExtension).to.be.calledWith(this.options.browser, this.options.isTextTerminal, this.options.proxyUrl, this.options.socketIoRoute) }) - it('writes extension and ensure write access', function () { + it('writes extension and ensure write access', async function () { // TODO: Test is failing locally, figure out why?? if (!process.env.CI) { return @@ -348,50 +392,49 @@ describe('lib/browsers/firefox', () => { }, mockfs.getMockRoot()) } - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(getFile(`${process.env.HOME }/.config/Cypress/cy/test/browsers/firefox-stable/interactive/CypressExtension/background.js`).getMode()).to.be.equals(0o644) - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + + expect(getFile(`${process.env.HOME }/.config/Cypress/cy/test/browsers/firefox-stable/interactive/CypressExtension/background.js`).getMode()).to.be.equals(0o644) }) - it('sets proxy-related preferences if specified', function () { + it('sets proxy-related preferences if specified', async function () { this.options.proxyServer = 'http://proxy-server:1234' - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.http', 'proxy-server') - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.ssl', 'proxy-server') - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.http_port', 1234) - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.ssl_port', 1234) + await firefox.open(this.browser, 'http://', this.options, this.automation) - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.no_proxies_on') - }) + expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.http', 'proxy-server') + expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.ssl', 'proxy-server') + expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.http_port', 1234) + expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.ssl_port', 1234) + + expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.no_proxies_on') }) - it('does not set proxy-related preferences if not specified', function () { - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(FirefoxProfile.prototype.setPreference).not.to.be.calledWith('network.proxy.http', 'proxy-server') - expect(FirefoxProfile.prototype.setPreference).not.to.be.calledWith('network.proxy.https', 'proxy-server') - expect(FirefoxProfile.prototype.setPreference).not.to.be.calledWith('network.proxy.http_port', 1234) - expect(FirefoxProfile.prototype.setPreference).not.to.be.calledWith('network.proxy.https_port', 1234) + it('does not set proxy-related preferences if not specified', async function () { + await firefox.open(this.browser, 'http://', this.options, this.automation) - expect(FirefoxProfile.prototype.setPreference).not.to.be.calledWith('network.proxy.no_proxies_on') - }) + expect(FirefoxProfile.prototype.setPreference).not.to.be.calledWith('network.proxy.http', 'proxy-server') + expect(FirefoxProfile.prototype.setPreference).not.to.be.calledWith('network.proxy.https', 'proxy-server') + expect(FirefoxProfile.prototype.setPreference).not.to.be.calledWith('network.proxy.http_port', 1234) + expect(FirefoxProfile.prototype.setPreference).not.to.be.calledWith('network.proxy.https_port', 1234) + + expect(FirefoxProfile.prototype.setPreference).not.to.be.calledWith('network.proxy.no_proxies_on') }) // @see https://github.com/cypress-io/cypress/issues/17896 - it('escapes the downloadsFolders path correctly when running on Windows OS', function () { + it('escapes the downloadsFolders path correctly when running on Windows OS', async function () { this.options.proxyServer = 'http://proxy-server:1234' this.options.downloadsFolder = 'C:/Users/test/Downloads/My_Test_Downloads_Folder' sinon.stub(os, 'platform').returns('win32') const executeBeforeBrowserLaunchSpy = sinon.spy(utils, 'executeBeforeBrowserLaunch') - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(executeBeforeBrowserLaunchSpy).to.have.been.calledWith(this.browser, sinon.match({ - preferences: { - // NOTE: sinon.match treats the string itself as a regular expression. The backslashes need to be escaped. - 'browser.download.dir': 'C:\\\\Users\\\\test\\\\Downloads\\\\My_Test_Downloads_Folder', - }, - }), this.options) - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + expect(executeBeforeBrowserLaunchSpy).to.have.been.calledWith(this.browser, sinon.match({ + preferences: { + // NOTE: sinon.match treats the string itself as a regular expression. The backslashes need to be escaped. + 'browser.download.dir': 'C:\\\\Users\\\\test\\\\Downloads\\\\My_Test_Downloads_Folder', + }, + }), this.options) }) // CDP is deprecated in Firefox 129 and up. @@ -399,31 +442,31 @@ describe('lib/browsers/firefox', () => { // remote.active-protocol=2 // @see https://fxdx.dev/deprecating-cdp-support-in-firefox-embracing-the-future-with-webdriver-bidi/ // @see https://github.com/cypress-io/cypress/issues/29713 - it('sets "remote.active-protocols"=2 to keep CDP enabled for firefox versions 129 and up', function () { + it('sets "remote.active-protocols"=2 to keep CDP enabled for firefox versions 129 and up', async function () { const executeBeforeBrowserLaunchSpy = sinon.spy(utils, 'executeBeforeBrowserLaunch') - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(executeBeforeBrowserLaunchSpy).to.have.been.calledWith(this.browser, sinon.match({ - preferences: { - 'remote.active-protocols': 2, - }, - }), this.options) - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + + expect(executeBeforeBrowserLaunchSpy).to.have.been.calledWith(this.browser, sinon.match({ + preferences: { + 'remote.active-protocols': 2, + }, + }), this.options) }) - it('updates the preferences', function () { - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(FirefoxProfile.prototype.updatePreferences).to.be.called - }) + it('updates the preferences', async function () { + await firefox.open(this.browser, 'http://', this.options, this.automation) + expect(FirefoxProfile.prototype.updatePreferences).to.be.called }) - it('resolves the browser instance', function () { - return firefox.open(this.browser, 'http://', this.options, this.automation).then((result) => { - expect(result).to.equal(this.browserInstance) - }) + it('resolves the browser instance as an event emitter', async function () { + const result = await firefox.open(this.browser, 'http://', this.options, this.automation) + + expect(result).to.be.an.instanceof(EventEmitter) + expect(result.kill).to.be.an.instanceof(Function) }) - it('does not clear user profile if already exists', function () { + it('does not clear user profile if already exists', async function () { mockfs({ '/path/to/appData/firefox-stable/interactive/': { 'xulstore.json': '[foo xulstore.json]', @@ -431,22 +474,21 @@ describe('lib/browsers/firefox', () => { }, }) - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - // @ts-ignore - expect(specUtil.getFsPath('/path/to/appData/firefox-stable/interactive')).containSubset({ - 'xulstore.json': '[foo xulstore.json]', - 'chrome': { 'userChrome.css': '[foo userChrome.css]' }, - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + + // @ts-ignore + expect(specUtil.getFsPath('/path/to/appData/firefox-stable/interactive')).containSubset({ + 'xulstore.json': '[foo xulstore.json]', + 'chrome': { 'userChrome.css': '[foo userChrome.css]' }, }) }) - it('creates chrome/userChrome.css if not exist', function () { - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(specUtil.getFsPath('/path/to/appData/firefox-stable/interactive/chrome/userChrome.css')).ok - }) + it('creates chrome/userChrome.css if not exist', async function () { + await firefox.open(this.browser, 'http://', this.options, this.automation) + expect(specUtil.getFsPath('/path/to/appData/firefox-stable/interactive/chrome/userChrome.css')).ok }) - it('clears browser cache', function () { + it('clears browser cache', async function () { mockfs({ '/path/to/appData/firefox-stable/interactive/': { 'CypressCache': { 'foo': 'bar' }, @@ -455,11 +497,10 @@ describe('lib/browsers/firefox', () => { this.options.isTextTerminal = false - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - // @ts-ignore - expect(specUtil.getFsPath('/path/to/appData/firefox-stable/interactive')).containSubset({ - 'CypressCache': {}, - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + // @ts-ignore + expect(specUtil.getFsPath('/path/to/appData/firefox-stable/interactive')).containSubset({ + 'CypressCache': {}, }) }) @@ -475,30 +516,42 @@ describe('lib/browsers/firefox', () => { }) }) - it('executes after:browser:launch if registered', function () { + it('executes after:browser:launch if registered', async function () { plugins.has.withArgs('after:browser:launch').returns(true) plugins.execute.resolves(null) - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(plugins.execute).to.be.calledWith('after:browser:launch', this.browser, { - webSocketDebuggerUrl: 'ws://debugger', - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + + expect(plugins.execute).to.be.calledWith('after:browser:launch', this.browser, { + webSocketDebuggerUrl: 'ws://debugger', }) }) - it('does not execute after:browser:launch if not registered', function () { + it('does not execute after:browser:launch if not registered', async function () { plugins.has.withArgs('after:browser:launch').returns(false) - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - expect(plugins.execute).not.to.be.calledWith('after:browser:launch') - }) + await firefox.open(this.browser, 'http://', this.options, this.automation) + expect(plugins.execute).not.to.be.calledWith('after:browser:launch') }) - context('returns BrowserInstance', function () { + context('returns BrowserInstanceWrapper as EventEmitter', function () { it('from browsers.launch', async function () { const instance = await firefox.open(this.browser, 'http://', this.options, this.automation) - expect(instance).to.eq(this.browserInstance) + expect(instance).to.be.an.instanceof(EventEmitter) + }) + + it('kills the driver and browser PIDs when the kill method is called', async function () { + sinon.stub(process, 'kill').returns(true) + const instance = await firefox.open(this.browser, 'http://', this.options, this.automation) + const killResult = instance.kill() + + expect(killResult).to.be.true + // kills the browser + expect(process.kill).to.have.been.calledWith(1234) + // kills the webdriver process/ geckodriver process + expect(process.kill).to.have.been.calledWith(5678) + expect(browserCriClient.close).to.have.been.called }) }) }) diff --git a/packages/server/test/unit/browsers/geckodriver/index_spec.ts b/packages/server/test/unit/browsers/geckodriver/index_spec.ts deleted file mode 100644 index b0d52505a361..000000000000 --- a/packages/server/test/unit/browsers/geckodriver/index_spec.ts +++ /dev/null @@ -1,242 +0,0 @@ -import Bluebird from 'bluebird' -import debug from 'debug' -import mockery from 'mockery' -import EventEmitter from 'events' -import { expect, sinon } from '../../../spec_helper' -import { GeckoDriver, type StartGeckoDriverArgs } from '../../../../lib/browsers/geckodriver' -import type Sinon from 'sinon' - -describe('lib/browsers/geckodriver', () => { - let geckoDriverMockProcess: any - let geckoDriverMockStart: Sinon.SinonStub - let waitPortPackageStub: Sinon.SinonStub - let mockOpts: StartGeckoDriverArgs - - beforeEach(() => { - geckoDriverMockProcess = new EventEmitter() - - geckoDriverMockStart = sinon.stub() - waitPortPackageStub = sinon.stub() - - geckoDriverMockProcess.stdout = new EventEmitter() - geckoDriverMockProcess.stderr = new EventEmitter() - geckoDriverMockProcess.kill = sinon.stub().returns(true) - - mockOpts = { - host: '127.0.0.1', - port: 3000, - marionetteHost: '127.0.0.1', - marionettePort: 3001, - webdriverBidiPort: 3002, - profilePath: 'path/to/profile', - binaryPath: 'path/to/binary', - } - - mockery.enable() - mockery.warnOnUnregistered(false) - - mockery.registerMock('wait-port', waitPortPackageStub) - - // we stub the dynamic require on the Class to make this easier to test - // @ts-expect-error - GeckoDriver.getGeckoDriverPackage = () => { - return { - start: geckoDriverMockStart, - } - } - }) - - afterEach(() => { - mockery.deregisterMock('geckodriver') - mockery.deregisterMock('wait-port') - mockery.disable() - }) - - describe('GeckoDriver.create', () => { - it('starts the geckodriver', async () => { - geckoDriverMockStart.resolves(geckoDriverMockProcess) - waitPortPackageStub.resolves() - - const geckoDriverInstanceWrapper = await GeckoDriver.create(mockOpts) - - expect(geckoDriverInstanceWrapper).to.equal(geckoDriverMockProcess) - - expect(geckoDriverMockStart).to.have.been.called.once - expect(geckoDriverMockStart).to.have.been.calledWith(sinon.match({ - host: '127.0.0.1', - port: 3000, - marionetteHost: '127.0.0.1', - marionettePort: 3001, - websocketPort: 3002, - profileRoot: 'path/to/profile', - binary: 'path/to/binary', - jsdebugger: false, - logNoTruncate: false, - log: 'error', - spawnOpts: {}, - })) - - expect(waitPortPackageStub).to.have.been.called.once - expect(waitPortPackageStub).to.have.been.calledWith(sinon.match({ - port: 3000, - timeout: 6000, - output: 'silent', - })) - }) - - it('allows overriding of default props when starting', async () => { - geckoDriverMockStart.resolves(geckoDriverMockProcess) - waitPortPackageStub.resolves() - - mockOpts.spawnOpts = { - MOZ_FOO: 'BAR', - } - - const geckoDriverInstanceWrapper = await GeckoDriver.create(mockOpts, 10000) - - expect(geckoDriverInstanceWrapper).to.equal(geckoDriverMockProcess) - - expect(geckoDriverMockStart).to.have.been.called.once - expect(geckoDriverMockStart).to.have.been.calledWith(sinon.match({ - host: '127.0.0.1', - port: 3000, - marionetteHost: '127.0.0.1', - marionettePort: 3001, - websocketPort: 3002, - profileRoot: 'path/to/profile', - binary: 'path/to/binary', - jsdebugger: false, - logNoTruncate: false, - log: 'error', - spawnOpts: { - MOZ_FOO: 'BAR', - }, - })) - - expect(waitPortPackageStub).to.have.been.called.once - expect(waitPortPackageStub).to.have.been.calledWith(sinon.match({ - port: 3000, - timeout: 11000, - output: 'silent', - })) - }) - - describe('debugging', () => { - afterEach(() => { - debug.disable() - }) - - it('sets additional arguments if "DEBUG=cypress-verbose:server:browsers:geckodriver" is set', async () => { - debug.enable('cypress-verbose:server:browsers:geckodriver') - geckoDriverMockStart.resolves(geckoDriverMockProcess) - - waitPortPackageStub.resolves() - - mockOpts.spawnOpts = { - MOZ_FOO: 'BAR', - } - - const geckoDriverInstanceWrapper = await GeckoDriver.create(mockOpts) - - expect(geckoDriverInstanceWrapper).to.equal(geckoDriverMockProcess) - - expect(geckoDriverMockStart).to.have.been.called.once - expect(geckoDriverMockStart).to.have.been.calledWith(sinon.match({ - host: '127.0.0.1', - port: 3000, - marionetteHost: '127.0.0.1', - marionettePort: 3001, - websocketPort: 3002, - profileRoot: 'path/to/profile', - binary: 'path/to/binary', - jsdebugger: true, - logNoTruncate: true, - log: 'debug', - spawnOpts: { - MOZ_FOO: 'BAR', - }, - })) - - expect(waitPortPackageStub).to.have.been.called.once - expect(waitPortPackageStub).to.have.been.calledWith(sinon.match({ - port: 3000, - timeout: 6000, - output: 'dots', - })) - }) - }) - - describe('throws if', () => { - it('geckodriver failed to start', async () => { - geckoDriverMockStart.rejects(new Error('I FAILED TO START')) - - try { - await GeckoDriver.create(mockOpts) - } catch (err) { - expect(err.isCypressErr).to.be.true - expect(err.type).to.equal('FIREFOX_GECKODRIVER_FAILURE') - - // what the debug logs will show - expect(err.details).to.contain('Error: I FAILED TO START') - - // what the user sees - expect(err.messageMarkdown).to.equal('Cypress could not connect to Firefox.\n\nAn unexpected error was received from GeckoDriver: `geckodriver:start`\n\nTo avoid this error, ensure that there are no other instances of Firefox launched by Cypress running.') - - return - } - - throw 'test did not enter catch as expected' - }) - - it('geckodriver failed to attach or took to long to register', async () => { - geckoDriverMockStart.resolves(geckoDriverMockProcess) - waitPortPackageStub.rejects(new Error('I DID NOT ATTACH OR TOOK TOO LONG!')) - - try { - await GeckoDriver.create(mockOpts) - } catch (err) { - expect(err.isCypressErr).to.be.true - expect(err.type).to.equal('FIREFOX_GECKODRIVER_FAILURE') - - // what the debug logs will show - expect(err.details).to.contain('Error: I DID NOT ATTACH OR TOOK TOO LONG!') - - // what the user sees - expect(err.messageMarkdown).to.equal('Cypress could not connect to Firefox.\n\nAn unexpected error was received from GeckoDriver: `geckodriver:start`\n\nTo avoid this error, ensure that there are no other instances of Firefox launched by Cypress running.') - - expect(geckoDriverMockProcess.kill).to.have.been.called.once - - return - } - - throw 'test did not enter catch as expected' - }) - - it('geckodriver times out starting', async () => { - geckoDriverMockStart.resolves(geckoDriverMockProcess) - // return a promise that does not resolve so the timeout is reached - waitPortPackageStub.resolves(new Bluebird(() => {})) - - try { - // timeout after 0 seconds - await GeckoDriver.create(mockOpts, 0) - } catch (err) { - expect(err.isCypressErr).to.be.true - expect(err.type).to.equal('FIREFOX_GECKODRIVER_FAILURE') - - // what the debug logs will show - expect(err.details).to.contain('TimeoutError: operation timed out') - - // what the user sees - expect(err.messageMarkdown).to.equal('Cypress could not connect to Firefox.\n\nAn unexpected error was received from GeckoDriver: `geckodriver:start`\n\nTo avoid this error, ensure that there are no other instances of Firefox launched by Cypress running.') - - expect(geckoDriverMockProcess.kill).to.have.been.called.once - - return - } - - throw 'test did not enter catch as expected' - }) - }) - }) -}) diff --git a/packages/server/test/unit/browsers/webdriver-classic/index_spec.ts b/packages/server/test/unit/browsers/webdriver-classic/index_spec.ts deleted file mode 100644 index d69cedf120a1..000000000000 --- a/packages/server/test/unit/browsers/webdriver-classic/index_spec.ts +++ /dev/null @@ -1,316 +0,0 @@ -import nock from 'nock' -import { expect } from '../../../spec_helper' -import { WebDriverClassic } from '../../../../lib/browsers/webdriver-classic' - -describe('lib/browsers/webdriver-classic', () => { - let mockSessionId: string - let mockOpts: { - host: string - port: number - } - let nockContext: nock.Scope - - beforeEach(() => { - mockSessionId = `123456-abcdef` - mockOpts = { - host: '127.0.0.1', - port: 3000, - } - - nockContext = nock(`http://${mockOpts.host}:${mockOpts.port}`) - }) - - afterEach(() => { - nock.cleanAll() - }) - - describe('WebDriverClassic.createSession', () => { - it('can create a session', async () => { - const newSessionScope = nockContext.post('/session', { - capabilities: { - alwaysMatch: { - acceptInsecureCerts: true, - binary: '/path/to/binary', - 'moz:firefoxOptions': { - args: ['-headless', '-new-instance'], - env: { - foo: 'bar', - }, - prefs: { - 'remote.active-protocols': 1, - }, - }, - 'moz:debuggerAddress': true, - }, - }, - }).reply(200, { - value: { - capabilities: { - acceptInsecureCerts: true, - browserName: 'firefox', - browserVersion: '130.0', - 'moz:accessibilityChecks': false, - 'moz:buildID': '20240829075237', - 'moz:geckodriverVersion': '0.35.0', - 'moz:headless': false, - 'moz:platformVersion': '23.3.0', - 'moz:profile': '/path/to/profile', - 'moz:processID': 12345, - 'moz:shutdownTimeout': 60000, - 'moz:windowless': false, - 'moz:webdriverClick': true, - 'pageLoadStrategy': 'normal', - platformName: 'mac', - proxy: {}, - setWindowRect: true, - strictFileInteractability: false, - timeouts: { - implicit: 0, - pageLoad: 300000, - script: 30000, - }, - unhandledPromptBehavior: 'dismiss and notify', - userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:130.0) Gecko/20100101 Firefox/130.0', - 'moz:debuggerAddress': '127.0.0.1:3001', - }, - sessionId: mockSessionId, - }, - }) - - const wdc = new WebDriverClassic(mockOpts.host, mockOpts.port) - - const { capabilities } = await wdc.createSession({ - capabilities: { - alwaysMatch: { - acceptInsecureCerts: true, - binary: '/path/to/binary', - 'moz:firefoxOptions': { - args: ['-headless', '-new-instance'], - env: { - foo: 'bar', - }, - prefs: { - 'remote.active-protocols': 1, - }, - }, - 'moz:debuggerAddress': true, - }, - }, - }) - - // test a few expected capabilities from the response - expect(capabilities.acceptInsecureCerts).to.be.true - expect(capabilities['moz:debuggerAddress']).to.equal('127.0.0.1:3001') - expect(capabilities.platformName).to.equal('mac') - - newSessionScope.done() - }) - - it('throws if session cannot be created (detailed)', () => { - nockContext.post('/session', { - capabilities: { - alwaysMatch: { - acceptInsecureCerts: true, - }, - }, - }).reply(500, { - value: { - error: 'session not created', - message: 'failed to set preferences: unknown error', - }, - }) - - const wdc = new WebDriverClassic(mockOpts.host, mockOpts.port) - - expect(wdc.createSession({ - capabilities: { - alwaysMatch: { - acceptInsecureCerts: true, - }, - }, - })).to.be.rejectedWith('500: Internal Server Error. session not created. failed to set preferences: unknown error.') - }) - - it('throws if session cannot be created (generic)', () => { - nockContext.post('/session', { - capabilities: { - alwaysMatch: { - acceptInsecureCerts: true, - }, - }, - }).reply(500) - - const wdc = new WebDriverClassic(mockOpts.host, mockOpts.port) - - expect(wdc.createSession({ - capabilities: { - alwaysMatch: { - acceptInsecureCerts: true, - }, - }, - })).to.be.rejectedWith('500: Internal Server Error.') - }) - }) - - describe('WebDriverClassic.installAddOn', () => { - it('can install extensions', async () => { - const installExtensionScope = nockContext.post(`/session/${mockSessionId}/moz/addon/install`, { - path: '/path/to/ext', - temporary: true, - }).reply(200) - - const wdc = new WebDriverClassic(mockOpts.host, mockOpts.port) - - // @ts-expect-error - wdc.sessionId = mockSessionId - - await wdc.installAddOn({ - path: '/path/to/ext', - temporary: true, - }) - - installExtensionScope.done() - }) - - it('throws if extension cannot be installed', () => { - nockContext.post(`/session/${mockSessionId}/moz/addon/install`, { - path: '/path/to/ext', - temporary: true, - }).reply(500) - - const wdc = new WebDriverClassic(mockOpts.host, mockOpts.port) - - // @ts-expect-error - wdc.sessionId = mockSessionId - - expect(wdc.installAddOn({ - path: '/path/to/ext', - temporary: true, - })).to.be.rejectedWith('500: Internal Server Error') - }) - }) - - describe('WebDriverClassic.getWindowHandles', () => { - it('returns the page contexts when the requests succeeds', async () => { - const expectedContexts = ['mock-context-id-1'] - - nockContext.get(`/session/${mockSessionId}/window/handles`).reply(200, { - value: expectedContexts, - }) - - const wdc = new WebDriverClassic(mockOpts.host, mockOpts.port) - - // @ts-expect-error - wdc.sessionId = mockSessionId - - const contexts = await wdc.getWindowHandles() - - expect(contexts).to.deep.equal(expectedContexts) - }) - - it('throws an error if the request fails', async () => { - nockContext.get(`/session/${mockSessionId}/window/handles`).reply(500) - - const wdc = new WebDriverClassic(mockOpts.host, mockOpts.port) - - // @ts-expect-error - wdc.sessionId = mockSessionId - - expect(wdc.getWindowHandles()).to.be.rejectedWith('500: Internal Server Error') - }) - }) - - describe('WebDriverClassic.switchToWindow', () => { - it('returns null when the requests succeeds', async () => { - nockContext.post(`/session/${mockSessionId}/window`, { - handle: 'mock-context-id', - }).reply(200, { - value: null, - }) - - const wdc = new WebDriverClassic(mockOpts.host, mockOpts.port) - - // @ts-expect-error - wdc.sessionId = mockSessionId - - const payload = await wdc.switchToWindow('mock-context-id') - - expect(payload).to.equal(null) - }) - - it('throws an error if the request fails', async () => { - nockContext.post(`/session/${mockSessionId}/window`, { - handle: 'mock-context-id', - }).reply(500) - - const wdc = new WebDriverClassic(mockOpts.host, mockOpts.port) - - // @ts-expect-error - wdc.sessionId = mockSessionId - - expect(wdc.switchToWindow('mock-context-id')).to.be.rejectedWith('500: Internal Server Error') - }) - }) - - describe('WebDriverClassic.navigate', () => { - let mockNavigationUrl = 'http://localhost:8080' - - it('returns null when the requests succeeds', async () => { - nockContext.post(`/session/${mockSessionId}/url`, { - url: mockNavigationUrl, - }).reply(200, { - value: null, - }) - - const wdc = new WebDriverClassic(mockOpts.host, mockOpts.port) - - // @ts-expect-error - wdc.sessionId = mockSessionId - - const payload = await wdc.navigate(mockNavigationUrl) - - expect(payload).to.equal(null) - }) - - it('throws an error if the request fails', async () => { - nockContext.post(`/session/${mockSessionId}/url`, { - url: mockNavigationUrl, - }).reply(500) - - const wdc = new WebDriverClassic(mockOpts.host, mockOpts.port) - - // @ts-expect-error - wdc.sessionId = mockSessionId - - expect(wdc.navigate(mockNavigationUrl)).to.be.rejectedWith('500: Internal Server Error') - }) - }) - - describe('WebDriverClassic.maximizeWindow', () => { - it('returns null when the requests succeeds', async () => { - nockContext.post(`/session/${mockSessionId}/window/maximize`).reply(200, { - value: null, - }) - - const wdc = new WebDriverClassic(mockOpts.host, mockOpts.port) - - // @ts-expect-error - wdc.sessionId = mockSessionId - - const payload = await wdc.maximizeWindow() - - expect(payload).to.equal(null) - }) - - it('throws an error if the request fails', async () => { - nockContext.post(`/session/${mockSessionId}/window/maximize`).reply(500) - - const wdc = new WebDriverClassic(mockOpts.host, mockOpts.port) - - // @ts-expect-error - wdc.sessionId = mockSessionId - - expect(wdc.maximizeWindow()).to.be.rejectedWith('500: Internal Server Error') - }) - }) -}) diff --git a/tooling/v8-snapshot/cache/darwin/snapshot-meta.json b/tooling/v8-snapshot/cache/darwin/snapshot-meta.json index 957bef5499d1..cb7981b5dc2a 100644 --- a/tooling/v8-snapshot/cache/darwin/snapshot-meta.json +++ b/tooling/v8-snapshot/cache/darwin/snapshot-meta.json @@ -344,8 +344,6 @@ "./node_modules/lodash/isBuffer.js", "./node_modules/lodash/lodash.js", "./node_modules/make-dir/node_modules/semver/semver.js", - "./node_modules/marionette-client/lib/marionette/index.js", - "./node_modules/marionette-client/lib/marionette/marionette.js", "./node_modules/methods/index.js", "./node_modules/mime/mime.js", "./node_modules/mocha-7.0.1/index.js", @@ -602,6 +600,7 @@ "./node_modules/uuid/dist/v4.js", "./node_modules/uuid/dist/v5.js", "./node_modules/verror/lib/verror.js", + "./node_modules/wait-port/node_modules/chalk/source/index.js", "./node_modules/ws/index.js", "./node_modules/ws/lib/buffer-util.js", "./node_modules/ws/lib/constants.js", @@ -867,6 +866,14 @@ "./packages/server/node_modules/readable-stream/lib/internal/streams/stream.js", "./packages/server/node_modules/readable-stream/readable.js", "./packages/server/node_modules/supports-color/index.js", + "./packages/server/node_modules/webdriver/build/index.js", + "./packages/server/node_modules/webdriver/node_modules/ws/index.js", + "./packages/server/node_modules/webdriver/node_modules/ws/lib/buffer-util.js", + "./packages/server/node_modules/webdriver/node_modules/ws/lib/constants.js", + "./packages/server/node_modules/webdriver/node_modules/ws/lib/receiver.js", + "./packages/server/node_modules/webdriver/node_modules/ws/lib/validation.js", + "./packages/server/node_modules/webdriver/node_modules/ws/lib/websocket-server.js", + "./packages/server/node_modules/webdriver/node_modules/ws/lib/websocket.js", "./packages/server/start-cypress.js", "./packages/server/v8-snapshot-entry.js", "./packages/socket/index.js", @@ -1761,10 +1768,10 @@ "./node_modules/dayjs/plugin/duration.js", "./node_modules/dayjs/plugin/relativeTime.js", "./node_modules/dayjs/plugin/updateLocale.js", - "./node_modules/debug/node_modules/ms/index.js", "./node_modules/debug/src/common.js", "./node_modules/dedent/dist/dedent.js", "./node_modules/deep-is/index.js", + "./node_modules/deepmerge-ts/dist/node/index.cjs", "./node_modules/define-data-property/index.js", "./node_modules/define-properties/index.js", "./node_modules/depd/index.js", @@ -2494,7 +2501,6 @@ "./node_modules/lodash/toString.js", "./node_modules/make-dir/node_modules/pify/index.js", "./node_modules/make-error/index.js", - "./node_modules/marionette-client/lib/marionette/message.js", "./node_modules/md5/md5.js", "./node_modules/media-typer/index.js", "./node_modules/merge-descriptors/index.js", @@ -3444,7 +3450,6 @@ "./node_modules/trash/node_modules/uuid/lib/rng.js", "./node_modules/trash/node_modules/uuid/v1.js", "./node_modules/trash/node_modules/uuid/v4.js", - "./node_modules/tree-kill/index.js", "./node_modules/truncate-utf8-bytes/lib/truncate.js", "./node_modules/ts-node/dist-raw/node-internal-constants.js", "./node_modules/ts-node/dist-raw/node-internal-errors.js", @@ -3569,6 +3574,15 @@ "./node_modules/value-or-promise/build/main/ValueOrPromise.js", "./node_modules/value-or-promise/build/main/index.js", "./node_modules/vary/index.js", + "./node_modules/wait-port/lib/errors/connection-error.js", + "./node_modules/wait-port/lib/errors/validation-error.js", + "./node_modules/wait-port/lib/output-functions/dots.js", + "./node_modules/wait-port/lib/output-functions/index.js", + "./node_modules/wait-port/lib/output-functions/silent.js", + "./node_modules/wait-port/lib/validate-parameters.js", + "./node_modules/wait-port/lib/wait-port.js", + "./node_modules/wait-port/node_modules/chalk/source/templates.js", + "./node_modules/wait-port/node_modules/chalk/source/util.js", "./node_modules/webidl-conversions/lib/index.js", "./node_modules/whatwg-url/lib/URL-impl.js", "./node_modules/whatwg-url/lib/URL.js", @@ -3979,6 +3993,7 @@ "./packages/server/lib/browsers/debug-cdp-connection.ts", "./packages/server/lib/browsers/electron.ts", "./packages/server/lib/browsers/firefox-util.ts", + "./packages/server/lib/browsers/geckodriver/index.ts", "./packages/server/lib/browsers/memory/cgroup-v1.ts", "./packages/server/lib/browsers/memory/default.ts", "./packages/server/lib/browsers/protocol.ts", @@ -4209,6 +4224,7 @@ "./packages/server/node_modules/p-queue/dist/priority-queue.js", "./packages/server/node_modules/path-key/index.js", "./packages/server/node_modules/path-to-regexp/index.js", + "./packages/server/node_modules/pump/index.js", "./packages/server/node_modules/readable-stream/lib/internal/streams/async_iterator.js", "./packages/server/node_modules/readable-stream/lib/internal/streams/destroy.js", "./packages/server/node_modules/readable-stream/lib/internal/streams/end-of-stream.js", @@ -4218,6 +4234,14 @@ "./packages/server/node_modules/serve-static/index.js", "./packages/server/node_modules/string-width/index.js", "./packages/server/node_modules/string-width/node_modules/strip-ansi/index.js", + "./packages/server/node_modules/webdriver/build/index.cjs", + "./packages/server/node_modules/webdriver/node_modules/ws/lib/event-target.js", + "./packages/server/node_modules/webdriver/node_modules/ws/lib/extension.js", + "./packages/server/node_modules/webdriver/node_modules/ws/lib/limiter.js", + "./packages/server/node_modules/webdriver/node_modules/ws/lib/permessage-deflate.js", + "./packages/server/node_modules/webdriver/node_modules/ws/lib/sender.js", + "./packages/server/node_modules/webdriver/node_modules/ws/lib/stream.js", + "./packages/server/node_modules/webdriver/node_modules/ws/lib/subprotocol.js", "./packages/socket/lib/utils.ts", "./packages/socket/node_modules/engine.io-parser/lib/commons.js", "./packages/socket/node_modules/engine.io-parser/lib/decodePacket.js", @@ -4271,5 +4295,5 @@ "./tooling/v8-snapshot/cache/darwin/snapshot-entry.js" ], "deferredHashFile": "yarn.lock", - "deferredHash": "9ab51832162435dec2de359d222b063dfdce4b3d555581562e6f2c4255bc1e9b" + "deferredHash": "41791992df9573aeebeb0439ed43ee444447c0dc506255e264fd64603c059a41" } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 427a8a621763..70321b443885 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5939,6 +5939,13 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== +"@promptbook/utils@0.70.0-1": + version "0.70.0-1" + resolved "https://registry.npmjs.org/@promptbook/utils/-/utils-0.70.0-1.tgz#a950f1db9397f1b21b72cae9e0b147ffb9a209da" + integrity sha512-qd2lLRRN+sE6UuNMi2tEeUUeb4zmXnxY5EMdfHVXNE+bqBDpUC7/aEfXgA3jnUXEr+xFjQ8PTFQgWvBMaKvw0g== + dependencies: + spacetrim "0.11.39" + "@puppeteer/browsers@1.7.1": version "1.7.1" resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.7.1.tgz#04f1e3aec4b87f50a7acc8f64be2149bda014f0a" @@ -5952,6 +5959,20 @@ unbzip2-stream "1.4.3" yargs "17.7.1" +"@puppeteer/browsers@^2.2.0": + version "2.4.0" + resolved "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.4.0.tgz#a0dd0f4e381e53f509109ae83b891db5972750f5" + integrity sha512-x8J1csfIygOwf6D6qUAZ0ASk3z63zPb7wkNeHRerCMh82qWKUrOgkuP005AJC8lDL6/evtXETGEJVcwykKT4/g== + dependencies: + debug "^4.3.6" + extract-zip "^2.0.1" + progress "^2.0.3" + proxy-agent "^6.4.0" + semver "^7.6.3" + tar-fs "^3.0.6" + unbzip2-stream "^1.4.3" + yargs "^17.7.2" + "@purge-icons/generated@0.8.1": version "0.8.1" resolved "https://registry.yarnpkg.com/@purge-icons/generated/-/generated-0.8.1.tgz#15544a9c9b2436e436d884828077f9d88df660e7" @@ -7775,10 +7796,12 @@ dependencies: "@types/node" "*" -"@types/node@*", "@types/node@>=10.0.0", "@types/node@^18.11.18", "@types/node@^18.17.5": - version "18.18.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.3.tgz#e5188135fc2909b46530c798ef49be65083be3fd" - integrity sha512-0OVfGupTl3NBFr8+iXpfZ8NR7jfFO+P1Q+IO/q0wbo02wYkP5gy36phojeYWpLQ6WAMjl+VfmqUk2YbUfp0irA== +"@types/node@*", "@types/node@>=10.0.0", "@types/node@^20.1.0": + version "20.16.9" + resolved "https://registry.npmjs.org/@types/node/-/node-20.16.9.tgz#1217c6cc77c4f3aaf4a6c76fb56b790e81e48120" + integrity sha512-rkvIVJxsOfBejxK7I0FO5sa2WxFmJCzoDwcd88+fq/CUfynNywTo/1/T6hyFz22CyztsnLS9nVlHOnTI36RH5w== + dependencies: + undici-types "~6.19.2" "@types/node@16.9.1": version "16.9.1" @@ -7795,6 +7818,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== +"@types/node@^18.11.18", "@types/node@^18.17.5": + version "18.18.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.3.tgz#e5188135fc2909b46530c798ef49be65083be3fd" + integrity sha512-0OVfGupTl3NBFr8+iXpfZ8NR7jfFO+P1Q+IO/q0wbo02wYkP5gy36phojeYWpLQ6WAMjl+VfmqUk2YbUfp0irA== + "@types/node@^8.0.7": version "8.10.66" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.66.tgz#dd035d409df322acc83dff62a602f12a5783bbb3" @@ -8256,6 +8284,11 @@ dependencies: "@types/node" "*" +"@types/which@^2.0.1": + version "2.0.2" + resolved "https://registry.npmjs.org/@types/which/-/which-2.0.2.tgz#54541d02d6b1daee5ec01ac0d1b37cecf37db1ae" + integrity sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw== + "@types/ws@^7.4.7": version "7.4.7" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" @@ -8263,10 +8296,10 @@ dependencies: "@types/node" "*" -"@types/ws@^8.5.10", "@types/ws@^8.5.5": - version "8.5.10" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.10.tgz#4acfb517970853fa6574a3a6886791d04a396787" - integrity sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A== +"@types/ws@^8.5.10", "@types/ws@^8.5.3", "@types/ws@^8.5.5": + version "8.5.12" + resolved "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz#619475fe98f35ccca2a2f6c137702d85ec247b7e" + integrity sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ== dependencies: "@types/node" "*" @@ -8730,16 +8763,60 @@ dependencies: vue-demi "*" -"@wdio/logger@^8.28.0": - version "8.38.0" - resolved "https://registry.npmjs.org/@wdio/logger/-/logger-8.38.0.tgz#a96406267e800bef9c58ac95de00f42ab0d3ac5c" - integrity sha512-kcHL86RmNbcQP+Gq/vQUGlArfU6IIcbbnNp32rRIraitomZow+iEoc519rdQmSVusDozMS5DZthkgDdxK+vz6Q== +"@wdio/config@9.0.0": + version "9.0.0" + resolved "https://registry.npmjs.org/@wdio/config/-/config-9.0.0.tgz#4022e996928e3f1b29436c1a3a446a464c319a39" + integrity sha512-OeRSEO3fTDMeKcGWoS39YO5lrMNT8qn+/E7ZcsG6NAbXu2o0ZfLDgDh1Guhe/a8s3LKc6dck5GxgFEuAylwlAw== + dependencies: + "@wdio/logger" "9.0.0" + "@wdio/types" "9.0.0" + "@wdio/utils" "9.0.0" + decamelize "^6.0.0" + deepmerge-ts "^7.0.3" + glob "^10.2.2" + import-meta-resolve "^4.0.0" + +"@wdio/logger@9.0.0", "@wdio/logger@^8.38.0", "@wdio/logger@^9.0.0": + version "9.0.0" + resolved "https://registry.npmjs.org/@wdio/logger/-/logger-9.0.0.tgz#f13ebacfce2903f31b8c6894bb152407de3cba79" + integrity sha512-DmmkVjxcCFUCFJVymca4/gQF4uTtevG4AF+jCzPUA4NByTnyjVtg8x83K0sG3/YX5SOxgc+JUhSdH8g5wceWSA== dependencies: chalk "^5.1.2" loglevel "^1.6.0" loglevel-plugin-prefix "^0.8.4" strip-ansi "^7.1.0" +"@wdio/protocols@9.0.0": + version "9.0.0" + resolved "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.0.0.tgz#bda1a6c02770711f5cf429b800da0af991b117e1" + integrity sha512-qM+TwCvFjmomX8oi0Ns8LXfG5dvXiqQKLaJt9Nj+JXxczSh6XsLnFTLQAcG9ynnU7uz2v1TqM11M5enj74WEAA== + +"@wdio/types@9.0.0": + version "9.0.0" + resolved "https://registry.npmjs.org/@wdio/types/-/types-9.0.0.tgz#0bc2e3dcc3a718a9042779ecbf953f30882a9bc8" + integrity sha512-XDqIjNCw2ftWKXWn8vTqqZAMtjSxwJwO8IAEQczgRB0fUCvvipkeT3ZobT5Z4Mo5uvLLTaOqJxb4nwPXOfVt/A== + dependencies: + "@types/node" "^20.1.0" + +"@wdio/utils@9.0.0": + version "9.0.0" + resolved "https://registry.npmjs.org/@wdio/utils/-/utils-9.0.0.tgz#4613dcd01944165a5c6004bb557ef20a51acde5b" + integrity sha512-MGtMGHf/rbMChD/qtPLpnZuF685W5gBnMhP5b8hNzB+riDJIFbl/e41Jqhf4scrkpXHtjBM8kdvXZEI6SW3AuA== + dependencies: + "@puppeteer/browsers" "^2.2.0" + "@wdio/logger" "9.0.0" + "@wdio/types" "9.0.0" + decamelize "^6.0.0" + deepmerge-ts "^7.0.3" + edgedriver "^5.6.1" + geckodriver "^4.3.3" + get-port "^7.0.0" + import-meta-resolve "^4.0.0" + locate-app "^2.2.24" + safaridriver "^0.1.2" + split2 "^4.2.0" + wait-port "^1.1.0" + "@webassemblyjs/ast@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" @@ -9180,7 +9257,7 @@ resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.36.0.tgz#7a1b53f4091e18d0b404873ea3e3c83589c765f2" integrity sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg== -"@zip.js/zip.js@^2.7.44": +"@zip.js/zip.js@^2.7.48": version "2.7.52" resolved "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.52.tgz#bc11de93b41f09e03155bc178e7f9c2e2612671d" integrity sha512-+5g7FQswvrCHwYKNMd/KFxZSObctLSsQOgqBSi0LzwHo3li9Eh1w5cF5ndjQw9Zbr3ajVnd2+XyiX85gAetx1Q== @@ -13306,12 +13383,12 @@ debug@3.2.6: dependencies: ms "^2.1.1" -debug@4, debug@4.3.4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.6, debug@~4.3.1: + version "4.3.7" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== dependencies: - ms "2.1.2" + ms "^2.1.3" debug@4.1.1: version "4.1.1" @@ -13334,6 +13411,13 @@ debug@4.3.3: dependencies: ms "2.1.2" +debug@4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debug@^3.1.0, debug@^3.2.6, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -13455,6 +13539,11 @@ deep-is@^0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +deepmerge-ts@^7.0.3: + version "7.1.0" + resolved "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.0.tgz#c1e0f11f64465b3e04ca4e03658235fba1cce07b" + integrity sha512-q6bNsfNBtgr8ZOQqmZbl94MmYWm+QcDNIkqCxVWiw1vKvf+y/N2dZQKdnDXn4c5Ygt/y63tDof6OCN+2YwWVEg== + deepmerge@^4.2.2, deepmerge@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" @@ -14255,6 +14344,27 @@ ecstatic@^3.3.2: minimist "^1.1.0" url-join "^2.0.5" +edge-paths@^3.0.5: + version "3.0.5" + resolved "https://registry.npmjs.org/edge-paths/-/edge-paths-3.0.5.tgz#9a35361d701d9b5dc07f641cebe8da01ede80937" + integrity sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg== + dependencies: + "@types/which" "^2.0.1" + which "^2.0.2" + +edgedriver@^5.6.1: + version "5.6.1" + resolved "https://registry.npmjs.org/edgedriver/-/edgedriver-5.6.1.tgz#36971f000aee8756c11f3fb1dc5273f109e860d5" + integrity sha512-3Ve9cd5ziLByUdigw6zovVeWJjVs8QHVmqOB0sJ0WNeVPcwf4p18GnxMmVvlFmYRloUwf5suNuorea4QzwBIOA== + dependencies: + "@wdio/logger" "^8.38.0" + "@zip.js/zip.js" "^2.7.48" + decamelize "^6.0.0" + edge-paths "^3.0.5" + fast-xml-parser "^4.4.1" + node-fetch "^3.3.2" + which "^4.0.0" + editorconfig@^0.15.3: version "0.15.3" resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5" @@ -15948,6 +16058,13 @@ fast-xml-parser@4.2.5: dependencies: strnum "^1.0.5" +fast-xml-parser@^4.4.1: + version "4.5.0" + resolved "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz#2882b7d01a6825dfdf909638f2de0256351def37" + integrity sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg== + dependencies: + strnum "^1.0.5" + fastest-levenshtein@^1.0.12, fastest-levenshtein@^1.0.16: version "1.0.16" resolved "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" @@ -16834,16 +16951,16 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -geckodriver@4.4.2: - version "4.4.2" - resolved "https://registry.npmjs.org/geckodriver/-/geckodriver-4.4.2.tgz#b5b72b3e5deb905947151f214b96f52505c2dd3a" - integrity sha512-/JFJ7DJPJUvDhLjzQk+DwjlkAmiShddfRHhZ/xVL9FWbza5Bi3UMGmmerEKqD69JbRs7R81ZW31co686mdYZyA== +geckodriver@4.5.0, geckodriver@^4.3.3: + version "4.5.0" + resolved "https://registry.npmjs.org/geckodriver/-/geckodriver-4.5.0.tgz#a2a4e526ac657af7d21089727218adddd750080f" + integrity sha512-EnBCT9kJ5oEoP3DaJKjzxAhm7bbNNK6k2q7oCkCT58OIOOiE6Hsr+nVDHflsNaR68HMGtBKOLSZ+YvCDHecScw== dependencies: - "@wdio/logger" "^8.28.0" - "@zip.js/zip.js" "^2.7.44" + "@wdio/logger" "^9.0.0" + "@zip.js/zip.js" "^2.7.48" decamelize "^6.0.0" http-proxy-agent "^7.0.2" - https-proxy-agent "^7.0.4" + https-proxy-agent "^7.0.5" node-fetch "^3.3.2" tar-fs "^3.0.6" which "^4.0.0" @@ -16919,6 +17036,11 @@ get-port@^3.2.0: resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" integrity sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw= +get-port@^7.0.0: + version "7.1.0" + resolved "https://registry.npmjs.org/get-port/-/get-port-7.1.0.tgz#d5a500ebfc7aa705294ec2b83cc38c5d0e364fec" + integrity sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw== + get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -18247,7 +18369,7 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" -http-proxy-agent@^7.0.0, http-proxy-agent@^7.0.2: +http-proxy-agent@^7.0.0, http-proxy-agent@^7.0.1, http-proxy-agent@^7.0.2: version "7.0.2" resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== @@ -18359,7 +18481,7 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -https-proxy-agent@^7.0.0, https-proxy-agent@^7.0.1, https-proxy-agent@^7.0.2, https-proxy-agent@^7.0.4: +https-proxy-agent@^7.0.0, https-proxy-agent@^7.0.1, https-proxy-agent@^7.0.2, https-proxy-agent@^7.0.3, https-proxy-agent@^7.0.5: version "7.0.5" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== @@ -20841,6 +20963,15 @@ local-pkg@^0.5.0: mlly "^1.4.2" pkg-types "^1.0.3" +locate-app@^2.2.24: + version "2.4.43" + resolved "https://registry.npmjs.org/locate-app/-/locate-app-2.4.43.tgz#5686a0e308b86889e7c88463a507186ca03ec1d5" + integrity sha512-BX6NEdECUGcDQw8aqqg02qLyF9rF8V+dAfyAnBzL2AofIlIvf4Q6EGXnzVWpWot9uBE+x/o8CjXHo7Zlegu91Q== + dependencies: + "@promptbook/utils" "0.70.0-1" + type-fest "2.13.0" + userhome "1.0.0" + locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -22575,7 +22706,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.2: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.2, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -25666,6 +25797,20 @@ proxy-agent@6.3.1: proxy-from-env "^1.1.0" socks-proxy-agent "^8.0.2" +proxy-agent@^6.4.0: + version "6.4.0" + resolved "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz#b4e2dd51dee2b377748aef8d45604c2d7608652d" + integrity sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ== + dependencies: + agent-base "^7.0.2" + debug "^4.3.4" + 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" + socks-proxy-agent "^8.0.2" + proxy-from-env@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" @@ -27224,6 +27369,11 @@ rxjs@^7.1.0, rxjs@^7.5.5: dependencies: tslib "^2.1.0" +safaridriver@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/safaridriver/-/safaridriver-0.1.2.tgz#166571d5881c7d6f884900d92d51ee1309c05aa4" + integrity sha512-4R309+gWflJktzPXBQCobbWEHlzC4aK3a+Ov3tz2Ib2aBxiwd11phkdIBH1l0EO22x24CJMUQkpKFumRriCSRg== + safe-array-concat@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" @@ -27530,7 +27680,7 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.0.0, semver@^7.1.1, semver@^7.1.2, semver@^7.1.3, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.2: +semver@^7.0.0, semver@^7.1.1, semver@^7.1.2, semver@^7.1.3, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.2, semver@^7.6.3: version "7.6.3" resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== @@ -28579,6 +28729,11 @@ sourcemap-codec@^1.4.8: resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== +spacetrim@0.11.39: + version "0.11.39" + resolved "https://registry.npmjs.org/spacetrim/-/spacetrim-0.11.39.tgz#9f606970741512c705fe4969139b0116e239deb3" + integrity sha512-S/baW29azJ7py5ausQRE2S6uEDQnlxgMHOEEq4V770ooBDD1/9kZnxRcco/tjZYuDuqYXblCk/r3N13ZmvHZ2g== + sparkles@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c" @@ -28684,7 +28839,7 @@ split2@^3.0.0: dependencies: readable-stream "^3.0.0" -split2@^4.0.0: +split2@^4.0.0, split2@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== @@ -30418,6 +30573,11 @@ type-detect@^1.0.0: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" integrity sha1-diIXzAbbJY7EiQihKY6LlRIejqI= +type-fest@2.13.0: + version "2.13.0" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-2.13.0.tgz#d1ecee38af29eb2e863b22299a3d68ef30d2abfb" + integrity sha512-lPfAm42MxE4/456+QyIaaVBAwgpJb6xZ8PRu09utnhPdWwcyj9vgy6Sq0Z5yNbJ21EdxB5dRU/Qg8bsyAMtlcw== + type-fest@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" @@ -30639,7 +30799,7 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -unbzip2-stream@1.4.3: +unbzip2-stream@1.4.3, unbzip2-stream@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== @@ -30681,6 +30841,11 @@ undertaker@^1.2.1: object.reduce "^1.0.0" undertaker-registry "^1.0.0" +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + unfetch@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.1.0.tgz#6ec2dd0de887e58a4dee83a050ded80ffc4137db" @@ -31042,6 +31207,11 @@ user-home@^2.0.0: dependencies: os-homedir "^1.0.0" +userhome@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/userhome/-/userhome-1.0.0.tgz#b6491ff12d21a5e72671df9ccc8717e1c6688c0b" + integrity sha512-ayFKY3H+Pwfy4W98yPdtH1VqH4psDeyW8lYYFzfecR9d6hqLpqhecktvYR3SEEXt7vG0S1JEpciI3g94pMErig== + utf8-byte-length@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" @@ -31496,7 +31666,7 @@ vuex@^4.0.0: resolved "https://registry.yarnpkg.com/vuex/-/vuex-4.0.0.tgz#ac877aa76a9c45368c979471e461b520d38e6cf5" integrity sha512-56VPujlHscP5q/e7Jlpqc40sja4vOhC4uJD1llBCWolVI8ND4+VzisDVkUMl+z5y0MpIImW6HjhNc+ZvuizgOw== -wait-port@1.1.0: +wait-port@1.1.0, wait-port@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/wait-port/-/wait-port-1.1.0.tgz#e5d64ee071118d985e2b658ae7ad32b2ce29b6b5" integrity sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q== @@ -31572,6 +31742,21 @@ web-streams-polyfill@^3.0.3: resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b" integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== +webdriver@9.0.0: + version "9.0.0" + resolved "https://registry.npmjs.org/webdriver/-/webdriver-9.0.0.tgz#9e07c1c5f963c09131c9ab3dbc5551cacb03d905" + integrity sha512-wcysboeZ1Ax6K7WPTF/vCNzegcdg+f453GOJd86ARE+wf3xRSQsvCZDwnEO8/7wvj/3xV9KMYPeuhPJ6b5VFvw== + dependencies: + "@types/node" "^20.1.0" + "@types/ws" "^8.5.3" + "@wdio/config" "9.0.0" + "@wdio/logger" "9.0.0" + "@wdio/protocols" "9.0.0" + "@wdio/types" "9.0.0" + "@wdio/utils" "9.0.0" + deepmerge-ts "^7.0.3" + ws "^8.8.0" + webextension-polyfill@0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.4.0.tgz#9cc5a60f0f2bf907a6b349fdd7e61701f54956f9" @@ -32234,10 +32419,10 @@ ws@^6.2.1: dependencies: async-limiter "~1.0.0" -ws@^8.0.0, ws@^8.13.0, ws@^8.16.0, ws@^8.5.0: - version "8.16.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" - integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== +ws@^8.0.0, ws@^8.13.0, ws@^8.16.0, ws@^8.5.0, ws@^8.8.0: + version "8.18.0" + resolved "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== ws@~8.11.0: version "8.11.0" @@ -32609,7 +32794,7 @@ yargs@^15.1.0, yargs@^15.3.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^17.0.0, yargs@^17.0.1, yargs@^17.5.1, yargs@^17.6.2: +yargs@^17.0.0, yargs@^17.0.1, yargs@^17.5.1, yargs@^17.6.2, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== From abf7294831c8d925b8bd6d0e5a5e1c95fa6607c0 Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Mon, 30 Sep 2024 09:57:54 -0400 Subject: [PATCH 02/22] misc: go back to xulstore to save browser preferences [run ci] --- .circleci/cache-version.txt | 2 +- packages/server/lib/browsers/firefox.ts | 41 ++++-- packages/server/package.json | 2 +- .../server/test/unit/browsers/firefox_spec.ts | 110 ++++++++++----- .../cache/darwin/snapshot-meta.json | 126 +++++------------- yarn.lock | 41 ++---- 6 files changed, 151 insertions(+), 171 deletions(-) diff --git a/.circleci/cache-version.txt b/.circleci/cache-version.txt index d1509d332c14..1df8e400e9b6 100644 --- a/.circleci/cache-version.txt +++ b/.circleci/cache-version.txt @@ -1,3 +1,3 @@ # Bump this version to force CI to re-create the cache from scratch. -09-30-24 +09-29-24 diff --git a/packages/server/lib/browsers/firefox.ts b/packages/server/lib/browsers/firefox.ts index daa6f1fce0f4..8f1b18b7ca17 100644 --- a/packages/server/lib/browsers/firefox.ts +++ b/packages/server/lib/browsers/firefox.ts @@ -482,15 +482,19 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc debug('firefox directories %o', { path: profile.path(), cacheDir, extensionDest }) - launchOptions.preferences['browser.cache.disk.parent_directory'] = cacheDir - for (const pref in launchOptions.preferences) { - const value = launchOptions.preferences[pref] + const xulStorePath = path.join(profile.path(), 'xulstore.json') + + // if user has set custom window.sizemode pref or it's the first time launching on this profile, write to xulStore. + if (!await fs.pathExists(xulStorePath)) { + // this causes the browser to launch maximized, which chrome does by default + // otherwise an arbitrary size will be picked for the window size + // this will not have an effect after first launch in 'interactive' mode + const sizemode = 'maximized' - profile.setPreference(pref, value) + await fs.writeJSON(xulStorePath, { 'chrome://browser/content/browser.xhtml': { 'main-window': { 'width': 1280, 'height': 1024, sizemode } } }) } - // TODO: fix this - synchronous FS operation - profile.updatePreferences() + launchOptions.preferences['browser.cache.disk.parent_directory'] = cacheDir const userCSSPath = path.join(profileDir, 'chrome') @@ -553,6 +557,22 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc logNoTruncate: Debug.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE), } + /** + * To set the profile, we use the profile capabilities in firefoxOptions which + * requires the profile to be base64 encoded. The profile will be copied over to whatever + * profile is created by geckodriver stemming from the root profile path. + * + * For example, if the profileRoot in geckodriver is /usr/foo/firefox-stable/run-12345, the new webdriver session + * will take the base64 encoded profile contents we created in /usr/foo/firefox-stable/run-12345/* (via firefox-profile npm package) and + * copy it to a profile created in the profile root, which would look something like /usr/foo/firefox-stable/run-12345/rust_mozprofile/* + * @see https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions + */ + const base64EncodedProfile = await new Promise((resolve, reject) => { + profile.encoded(function (err, encodedProfile) { + err ? reject(err) : resolve(encodedProfile) + }) + }) + const newSessionCapabilities: RemoteConfig = { logLevel: Debug.enabled(WEBDRIVER_DEBUG_NAMESPACE_VERBOSE) ? 'info' : 'silent', capabilities: { @@ -561,6 +581,7 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc acceptInsecureCerts: true, // @see https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions 'moz:firefoxOptions': { + profile: base64EncodedProfile, binary: browser.path, args: launchOptions.args, prefs: launchOptions.preferences, @@ -622,14 +643,6 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc // makes it so get getRemoteDebuggingPort() is calculated correctly process.env.CYPRESS_REMOTE_DEBUGGING_PORT = cdpPort.toString() - // maximize the window if running headful and no width or height args are provided. - // NOTE: We used to do this with xulstore.json, but this is no longer possible with geckodriver - // as firefox will create the profile under the profile root that we cannot control and we cannot consistently provide - // a base 64 encoded profile. - if (!browser.isHeadless && (!launchOptions.args.includes('-width') || !launchOptions.args.includes('-height'))) { - await webdriverClient.maximizeWindow() - } - // install the browser extensions await Promise.all(_.map(launchOptions.extensions, async (path) => { debug(`installing extension at path: ${path}`) diff --git a/packages/server/package.json b/packages/server/package.json index 486f2dddd304..874456b4d48a 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -68,7 +68,7 @@ "express": "4.21.0", "fetch-retry-ts": "^1.3.1", "find-process": "1.4.7", - "firefox-profile": "4.6.0", + "firefox-profile": "4.7.0", "fluent-ffmpeg": "2.1.2", "fs-extra": "9.1.0", "geckodriver": "4.5.0", diff --git a/packages/server/test/unit/browsers/firefox_spec.ts b/packages/server/test/unit/browsers/firefox_spec.ts index 994a1c98cbef..7d95aaa0390b 100644 --- a/packages/server/test/unit/browsers/firefox_spec.ts +++ b/packages/server/test/unit/browsers/firefox_spec.ts @@ -174,7 +174,19 @@ describe('lib/browsers/firefox', () => { plugins.execute.resolves(null) await firefox.open(this.browser, 'http://', this.options, this.automation) - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.type', 1) + + expect(webdriver.newSession).to.have.been.calledWith(sinon.match({ + capabilities: { + alwaysMatch: { + 'moz:firefoxOptions': { + prefs: { + 'network.proxy.type': 1, + }, + }, + }, + firstMatch: [], + }, + })) }) it('uses default preferences if before:browser:launch returns object with non-object preferences', async function () { @@ -184,7 +196,19 @@ describe('lib/browsers/firefox', () => { }) await firefox.open(this.browser, 'http://', this.options, this.automation) - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.type', 1) + + expect(webdriver.newSession).to.have.been.calledWith(sinon.match({ + capabilities: { + alwaysMatch: { + 'moz:firefoxOptions': { + prefs: { + 'network.proxy.type': 1, + }, + }, + }, + firstMatch: [], + }, + })) }) it('sets preferences if returned by before:browser:launch', async function () { @@ -195,7 +219,18 @@ describe('lib/browsers/firefox', () => { await firefox.open(this.browser, 'http://', this.options, this.automation) - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('foo', 'bar') + expect(webdriver.newSession).to.have.been.calledWith(sinon.match({ + capabilities: { + alwaysMatch: { + 'moz:firefoxOptions': { + prefs: { + 'foo': 'bar', + }, + }, + }, + firstMatch: [], + }, + })) }) it('creates the WebDriver session and geckodriver instance through capabilities, installs the extension, and passes the correct port to CDP', async function () { @@ -327,31 +362,23 @@ describe('lib/browsers/firefox', () => { expect(wdInstance.maximizeWindow).not.to.have.been.called }) - it('does not maximize the browser if "-width" or "-height" arg is set', async function () { - this.browser.isHeadless = false - sinon.stub(utils, 'executeBeforeBrowserLaunch').resolves({ - args: ['-width', '1280', '-height', '720'], - extensions: [], - preferences: {}, - }) - - await firefox.open(this.browser, 'http://', this.options, this.automation) - expect(wdInstance.maximizeWindow).not.to.have.been.called - }) - - it('maximizes the browser if headed and no "-width" or "-height" arg is set', async function () { - this.browser.isHeadless = false - - await firefox.open(this.browser, 'http://', this.options, this.automation) - - expect(wdInstance.maximizeWindow).to.have.been.called - }) - it('sets user-agent preference if specified', async function () { this.options.userAgent = 'User Agent' await firefox.open(this.browser, 'http://', this.options, this.automation) - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('general.useragent.override', 'User Agent') + + expect(webdriver.newSession).to.have.been.calledWith(sinon.match({ + capabilities: { + alwaysMatch: { + 'moz:firefoxOptions': { + prefs: { + 'general.useragent.override': 'User Agent', + }, + }, + }, + firstMatch: [], + }, + })) }) it('writes extension', async function () { @@ -402,12 +429,22 @@ describe('lib/browsers/firefox', () => { await firefox.open(this.browser, 'http://', this.options, this.automation) - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.http', 'proxy-server') - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.ssl', 'proxy-server') - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.http_port', 1234) - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.ssl_port', 1234) - - expect(FirefoxProfile.prototype.setPreference).to.be.calledWith('network.proxy.no_proxies_on') + expect(webdriver.newSession).to.have.been.calledWith(sinon.match({ + capabilities: { + alwaysMatch: { + 'moz:firefoxOptions': { + prefs: { + 'network.proxy.http': 'proxy-server', + 'network.proxy.ssl': 'proxy-server', + 'network.proxy.http_port': 1234, + 'network.proxy.ssl_port': 1234, + 'network.proxy.no_proxies_on': '', + }, + }, + }, + firstMatch: [], + }, + })) }) it('does not set proxy-related preferences if not specified', async function () { @@ -454,11 +491,6 @@ describe('lib/browsers/firefox', () => { }), this.options) }) - it('updates the preferences', async function () { - await firefox.open(this.browser, 'http://', this.options, this.automation) - expect(FirefoxProfile.prototype.updatePreferences).to.be.called - }) - it('resolves the browser instance as an event emitter', async function () { const result = await firefox.open(this.browser, 'http://', this.options, this.automation) @@ -483,6 +515,14 @@ describe('lib/browsers/firefox', () => { }) }) + it('creates xulstore.json if not exist', async function () { + await firefox.open(this.browser, 'http://', this.options, this.automation) + // @ts-ignore + expect(specUtil.getFsPath('/path/to/appData/firefox-stable/interactive')).containSubset({ + 'xulstore.json': '{"chrome://browser/content/browser.xhtml":{"main-window":{"width":1280,"height":1024,"sizemode":"maximized"}}}\n', + }) + }) + it('creates chrome/userChrome.css if not exist', async function () { await firefox.open(this.browser, 'http://', this.options, this.automation) expect(specUtil.getFsPath('/path/to/appData/firefox-stable/interactive/chrome/userChrome.css')).ok diff --git a/tooling/v8-snapshot/cache/darwin/snapshot-meta.json b/tooling/v8-snapshot/cache/darwin/snapshot-meta.json index cb7981b5dc2a..1b82f1ce43f7 100644 --- a/tooling/v8-snapshot/cache/darwin/snapshot-meta.json +++ b/tooling/v8-snapshot/cache/darwin/snapshot-meta.json @@ -225,9 +225,6 @@ "./node_modules/async/dist/async.js", "./node_modules/basic-auth/node_modules/safe-buffer/index.js", "./node_modules/black-hole-stream/index.js", - "./node_modules/body-parser/index.js", - "./node_modules/body-parser/node_modules/debug/src/browser.js", - "./node_modules/body-parser/node_modules/debug/src/index.js", "./node_modules/buffer-from/index.js", "./node_modules/chalk/index.js", "./node_modules/chrome-remote-interface/index.js", @@ -270,19 +267,9 @@ "./node_modules/express-graphql/node_modules/depd/index.js", "./node_modules/express-graphql/node_modules/http-errors/index.js", "./node_modules/express-graphql/parseBody.js", - "./node_modules/express/lib/application.js", - "./node_modules/express/lib/request.js", - "./node_modules/express/lib/response.js", - "./node_modules/express/lib/router/index.js", - "./node_modules/express/lib/router/route.js", - "./node_modules/express/node_modules/debug/src/browser.js", - "./node_modules/express/node_modules/debug/src/index.js", - "./node_modules/express/node_modules/send/index.js", "./node_modules/fast-glob/out/settings.js", "./node_modules/fast-glob/out/utils/path.js", "./node_modules/file-uri-to-path/index.js", - "./node_modules/finalhandler/node_modules/debug/src/browser.js", - "./node_modules/finalhandler/node_modules/debug/src/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/fs/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/json/index.js", @@ -520,10 +507,6 @@ "./node_modules/send/index.js", "./node_modules/send/node_modules/debug/src/browser.js", "./node_modules/send/node_modules/debug/src/index.js", - "./node_modules/serve-static/node_modules/debug/src/browser.js", - "./node_modules/serve-static/node_modules/debug/src/index.js", - "./node_modules/serve-static/node_modules/debug/src/node.js", - "./node_modules/serve-static/node_modules/send/index.js", "./node_modules/shell-env/node_modules/execa/lib/errname.js", "./node_modules/shell-env/node_modules/get-stream/buffer-stream.js", "./node_modules/shell-env/node_modules/semver/semver.js", @@ -600,7 +583,6 @@ "./node_modules/uuid/dist/v4.js", "./node_modules/uuid/dist/v5.js", "./node_modules/verror/lib/verror.js", - "./node_modules/wait-port/node_modules/chalk/source/index.js", "./node_modules/ws/index.js", "./node_modules/ws/lib/buffer-util.js", "./node_modules/ws/lib/constants.js", @@ -666,11 +648,16 @@ "./packages/errors/index.js", "./packages/errors/src/errTemplate.ts", "./packages/graphql/index.js", + "./packages/graphql/node_modules/body-parser/index.js", "./packages/graphql/node_modules/chalk/node_modules/supports-color/index.js", "./packages/graphql/node_modules/chalk/source/index.js", "./packages/graphql/node_modules/debug/src/browser.js", "./packages/graphql/node_modules/debug/src/index.js", - "./packages/graphql/node_modules/supports-color/index.js", + "./packages/graphql/node_modules/express/lib/application.js", + "./packages/graphql/node_modules/express/lib/request.js", + "./packages/graphql/node_modules/express/lib/response.js", + "./packages/graphql/node_modules/express/lib/router/index.js", + "./packages/graphql/node_modules/express/lib/router/route.js", "./packages/graphql/src/makeGraphQLServer.ts", "./packages/graphql/src/plugins/index.ts", "./packages/graphql/src/plugins/nexusDebugFieldPlugin.ts", @@ -866,14 +853,6 @@ "./packages/server/node_modules/readable-stream/lib/internal/streams/stream.js", "./packages/server/node_modules/readable-stream/readable.js", "./packages/server/node_modules/supports-color/index.js", - "./packages/server/node_modules/webdriver/build/index.js", - "./packages/server/node_modules/webdriver/node_modules/ws/index.js", - "./packages/server/node_modules/webdriver/node_modules/ws/lib/buffer-util.js", - "./packages/server/node_modules/webdriver/node_modules/ws/lib/constants.js", - "./packages/server/node_modules/webdriver/node_modules/ws/lib/receiver.js", - "./packages/server/node_modules/webdriver/node_modules/ws/lib/validation.js", - "./packages/server/node_modules/webdriver/node_modules/ws/lib/websocket-server.js", - "./packages/server/node_modules/webdriver/node_modules/ws/lib/websocket.js", "./packages/server/start-cypress.js", "./packages/server/v8-snapshot-entry.js", "./packages/socket/index.js", @@ -1598,18 +1577,6 @@ "./node_modules/binary-extensions/index.js", "./node_modules/binaryextensions/edition-es5/index.js", "./node_modules/bindings/bindings.js", - "./node_modules/body-parser/lib/read.js", - "./node_modules/body-parser/lib/types/json.js", - "./node_modules/body-parser/lib/types/raw.js", - "./node_modules/body-parser/lib/types/text.js", - "./node_modules/body-parser/lib/types/urlencoded.js", - "./node_modules/body-parser/node_modules/debug/src/debug.js", - "./node_modules/body-parser/node_modules/ms/index.js", - "./node_modules/body-parser/node_modules/qs/lib/formats.js", - "./node_modules/body-parser/node_modules/qs/lib/index.js", - "./node_modules/body-parser/node_modules/qs/lib/parse.js", - "./node_modules/body-parser/node_modules/qs/lib/stringify.js", - "./node_modules/body-parser/node_modules/qs/lib/utils.js", "./node_modules/braces/index.js", "./node_modules/braces/lib/compile.js", "./node_modules/braces/lib/constants.js", @@ -1771,7 +1738,6 @@ "./node_modules/debug/src/common.js", "./node_modules/dedent/dist/dedent.js", "./node_modules/deep-is/index.js", - "./node_modules/deepmerge-ts/dist/node/index.cjs", "./node_modules/define-data-property/index.js", "./node_modules/define-properties/index.js", "./node_modules/depd/index.js", @@ -1868,24 +1834,6 @@ "./node_modules/express-graphql/node_modules/statuses/index.js", "./node_modules/express-graphql/node_modules/toidentifier/index.js", "./node_modules/express-graphql/renderGraphiQL.js", - "./node_modules/express/index.js", - "./node_modules/express/lib/express.js", - "./node_modules/express/lib/middleware/init.js", - "./node_modules/express/lib/middleware/query.js", - "./node_modules/express/lib/router/layer.js", - "./node_modules/express/lib/utils.js", - "./node_modules/express/lib/view.js", - "./node_modules/express/node_modules/cookie/index.js", - "./node_modules/express/node_modules/debug/src/debug.js", - "./node_modules/express/node_modules/merge-descriptors/index.js", - "./node_modules/express/node_modules/ms/index.js", - "./node_modules/express/node_modules/path-to-regexp/index.js", - "./node_modules/express/node_modules/qs/lib/formats.js", - "./node_modules/express/node_modules/qs/lib/index.js", - "./node_modules/express/node_modules/qs/lib/parse.js", - "./node_modules/express/node_modules/qs/lib/stringify.js", - "./node_modules/express/node_modules/qs/lib/utils.js", - "./node_modules/express/node_modules/send/node_modules/ms/index.js", "./node_modules/ext-list/index.js", "./node_modules/ext-name/index.js", "./node_modules/extend/index.js", @@ -1915,9 +1863,6 @@ "./node_modules/fast-glob/out/utils/string.js", "./node_modules/fastq/queue.js", "./node_modules/fill-range/index.js", - "./node_modules/finalhandler/index.js", - "./node_modules/finalhandler/node_modules/debug/src/debug.js", - "./node_modules/finalhandler/node_modules/ms/index.js", "./node_modules/find-process/index.js", "./node_modules/find-process/lib/find.js", "./node_modules/find-process/lib/find_pid.js", @@ -1925,8 +1870,7 @@ "./node_modules/find-process/lib/utils.js", "./node_modules/firefox-profile/lib/firefox_profile.js", "./node_modules/firefox-profile/lib/profile_finder.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy-sync/copy-sync.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy-sync/index.js", + "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy/copy-sync.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy/copy.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/empty/index.js", @@ -1940,17 +1884,15 @@ "./node_modules/firefox-profile/node_modules/fs-extra/lib/json/output-json.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/mkdirs/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/mkdirs/make-dir.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/move-sync/index.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/move-sync/move-sync.js", + "./node_modules/firefox-profile/node_modules/fs-extra/lib/mkdirs/utils.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/move/index.js", + "./node_modules/firefox-profile/node_modules/fs-extra/lib/move/move-sync.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/move/move.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/output/index.js", + "./node_modules/firefox-profile/node_modules/fs-extra/lib/output-file/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/remove/index.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/remove/rimraf.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/util/stat.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/util/utimes.js", - "./node_modules/firefox-profile/node_modules/ini/ini.js", - "./node_modules/firefox-profile/node_modules/jsonfile/node_modules/universalify/index.js", + "./node_modules/firefox-profile/node_modules/ini/lib/ini.js", "./node_modules/firefox-profile/node_modules/jsonfile/utils.js", "./node_modules/firefox-profile/node_modules/universalify/index.js", "./node_modules/fluent-ffmpeg/lib/capabilities.js", @@ -3317,9 +3259,6 @@ "./node_modules/semver/ranges/valid.js", "./node_modules/send/node_modules/debug/node_modules/ms/index.js", "./node_modules/send/node_modules/debug/src/debug.js", - "./node_modules/serve-static/index.js", - "./node_modules/serve-static/node_modules/debug/node_modules/ms/index.js", - "./node_modules/serve-static/node_modules/debug/src/debug.js", "./node_modules/server-destroy/index.js", "./node_modules/set-function-length/index.js", "./node_modules/setprototypeof/index.js", @@ -3574,15 +3513,6 @@ "./node_modules/value-or-promise/build/main/ValueOrPromise.js", "./node_modules/value-or-promise/build/main/index.js", "./node_modules/vary/index.js", - "./node_modules/wait-port/lib/errors/connection-error.js", - "./node_modules/wait-port/lib/errors/validation-error.js", - "./node_modules/wait-port/lib/output-functions/dots.js", - "./node_modules/wait-port/lib/output-functions/index.js", - "./node_modules/wait-port/lib/output-functions/silent.js", - "./node_modules/wait-port/lib/validate-parameters.js", - "./node_modules/wait-port/lib/wait-port.js", - "./node_modules/wait-port/node_modules/chalk/source/templates.js", - "./node_modules/wait-port/node_modules/chalk/source/util.js", "./node_modules/webidl-conversions/lib/index.js", "./node_modules/whatwg-url/lib/URL-impl.js", "./node_modules/whatwg-url/lib/URL.js", @@ -3863,10 +3793,28 @@ "./packages/extension/lib/util.js", "./packages/frontend-shared/cypress/e2e/prod-dependencies.ts", "./packages/frontend-shared/cypress/e2e/v8-snapshot-entry.ts", + "./packages/graphql/node_modules/body-parser/lib/read.js", + "./packages/graphql/node_modules/body-parser/lib/types/json.js", + "./packages/graphql/node_modules/body-parser/lib/types/raw.js", + "./packages/graphql/node_modules/body-parser/lib/types/text.js", + "./packages/graphql/node_modules/body-parser/lib/types/urlencoded.js", "./packages/graphql/node_modules/chalk/source/templates.js", "./packages/graphql/node_modules/chalk/source/util.js", - "./packages/graphql/node_modules/debug/src/common.js", + "./packages/graphql/node_modules/cookie/index.js", + "./packages/graphql/node_modules/debug/node_modules/ms/index.js", + "./packages/graphql/node_modules/debug/src/debug.js", + "./packages/graphql/node_modules/encodeurl/index.js", + "./packages/graphql/node_modules/express/index.js", + "./packages/graphql/node_modules/express/lib/express.js", + "./packages/graphql/node_modules/express/lib/middleware/init.js", + "./packages/graphql/node_modules/express/lib/middleware/query.js", + "./packages/graphql/node_modules/express/lib/router/layer.js", + "./packages/graphql/node_modules/express/lib/utils.js", + "./packages/graphql/node_modules/express/lib/view.js", + "./packages/graphql/node_modules/finalhandler/index.js", "./packages/graphql/node_modules/has-flag/index.js", + "./packages/graphql/node_modules/path-to-regexp/index.js", + "./packages/graphql/node_modules/serve-static/index.js", "./packages/graphql/src/index.ts", "./packages/https-proxy/lib/proxy.js", "./packages/https-proxy/lib/server.js", @@ -3993,15 +3941,16 @@ "./packages/server/lib/browsers/debug-cdp-connection.ts", "./packages/server/lib/browsers/electron.ts", "./packages/server/lib/browsers/firefox-util.ts", - "./packages/server/lib/browsers/geckodriver/index.ts", "./packages/server/lib/browsers/memory/cgroup-v1.ts", "./packages/server/lib/browsers/memory/default.ts", "./packages/server/lib/browsers/protocol.ts", + "./packages/server/lib/browsers/webdriver/index.ts", "./packages/server/lib/browsers/webkit-automation.ts", "./packages/server/lib/browsers/webkit.ts", "./packages/server/lib/cloud/api/scrub_url.ts", "./packages/server/lib/cloud/artifacts/artifact.ts", "./packages/server/lib/cloud/artifacts/file_upload_strategy.ts", + "./packages/server/lib/cloud/artifacts/print_protocol_upload_error.ts", "./packages/server/lib/cloud/artifacts/upload_artifacts.ts", "./packages/server/lib/cloud/encryption.ts", "./packages/server/lib/cloud/environment.ts", @@ -4014,6 +3963,7 @@ "./packages/server/lib/cloud/protocol.ts", "./packages/server/lib/cloud/upload/send_file.ts", "./packages/server/lib/cloud/upload/stream_activity_monitor.ts", + "./packages/server/lib/cloud/upload/stream_stalled_error.ts", "./packages/server/lib/cohorts.ts", "./packages/server/lib/controllers/client.js", "./packages/server/lib/controllers/files.js", @@ -4234,14 +4184,6 @@ "./packages/server/node_modules/serve-static/index.js", "./packages/server/node_modules/string-width/index.js", "./packages/server/node_modules/string-width/node_modules/strip-ansi/index.js", - "./packages/server/node_modules/webdriver/build/index.cjs", - "./packages/server/node_modules/webdriver/node_modules/ws/lib/event-target.js", - "./packages/server/node_modules/webdriver/node_modules/ws/lib/extension.js", - "./packages/server/node_modules/webdriver/node_modules/ws/lib/limiter.js", - "./packages/server/node_modules/webdriver/node_modules/ws/lib/permessage-deflate.js", - "./packages/server/node_modules/webdriver/node_modules/ws/lib/sender.js", - "./packages/server/node_modules/webdriver/node_modules/ws/lib/stream.js", - "./packages/server/node_modules/webdriver/node_modules/ws/lib/subprotocol.js", "./packages/socket/lib/utils.ts", "./packages/socket/node_modules/engine.io-parser/lib/commons.js", "./packages/socket/node_modules/engine.io-parser/lib/decodePacket.js", @@ -4295,5 +4237,5 @@ "./tooling/v8-snapshot/cache/darwin/snapshot-entry.js" ], "deferredHashFile": "yarn.lock", - "deferredHash": "41791992df9573aeebeb0439ed43ee444447c0dc506255e264fd64603c059a41" + "deferredHash": "7186aa2740a0751567e15f6fb7493ba7ae01f37845157c0fa91257bee987a635" } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 70321b443885..c2c06acb5cd0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16469,16 +16469,16 @@ fined@^1.0.1: object.pick "^1.2.0" parse-filepath "^1.0.1" -firefox-profile@4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/firefox-profile/-/firefox-profile-4.6.0.tgz#e819b2f75a05b4d215d0c30a74d5b9d2d9ba8ae1" - integrity sha512-I9rAm1w8U3CdhgO4EzTJsCvgcbvynZn9lOySkZf78wUdUIQH2w9QOKf3pAX+THt2XMSSR3kJSuM8P7bYux9j8g== +firefox-profile@4.7.0: + version "4.7.0" + resolved "https://registry.npmjs.org/firefox-profile/-/firefox-profile-4.7.0.tgz#97087b17a9a38fea58ec0acf2bca19a5cc121cb7" + integrity sha512-aGApEu5bfCNbA4PGUZiRJAIU6jKmghV2UVdklXAofnNtiDjqYw0czLS46W7IfFqVKgKhFB8Ao2YoNGHY4BoIMQ== dependencies: adm-zip "~0.5.x" - fs-extra "~9.0.1" - ini "~2.0.0" - minimist "^1.2.5" - xml2js "^0.5.0" + fs-extra "^11.2.0" + ini "^4.1.3" + minimist "^1.2.8" + xml2js "^0.6.2" flagged-respawn@^1.0.0: version "1.0.1" @@ -16778,16 +16778,6 @@ fs-extra@^7.0.1: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@~9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc" - integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^1.0.0" - fs-minipass@^2.0.0, fs-minipass@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" @@ -18730,7 +18720,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@2.0.0, ini@~2.0.0: +ini@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== @@ -30979,11 +30969,6 @@ universalify@^0.2.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== -universalify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d" - integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug== - universalify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" @@ -32470,10 +32455,10 @@ xml2js@^0.4.5: sax ">=0.6.0" xmlbuilder "~11.0.0" -xml2js@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7" - integrity sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA== +xml2js@^0.6.2: + version "0.6.2" + resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499" + integrity sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA== dependencies: sax ">=0.6.0" xmlbuilder "~11.0.0" From c7c23f1a4c40804ae870c79deb68f9da7e752bc4 Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Mon, 30 Sep 2024 17:52:28 -0400 Subject: [PATCH 03/22] add changelog [run ci] --- cli/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index e26eae8263ef..b7035f88c3cf 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -6,6 +6,8 @@ _Released 10/1/2024 (PENDING)_ **Misc:** - Cypress now consumes [geckodriver](https://firefox-source-docs.mozilla.org/testing/geckodriver/index.html) to help automate the Firefox browser instead of [marionette-client](https://github.com/cypress-io/marionette-client). Addresses [#30217](https://github.com/cypress-io/cypress/issues/30217). +- Cypress now consumes [webdriver](https://github.com/webdriverio/webdriverio/tree/main/packages/webdriver) to help automate the Firefox browser. Addresses [#30301](https://github.com/cypress-io/cypress/issues/30301). +- Cypress now uses [firefox-profile](https://github.com/saadtazi/firefox-profile-js) to create a firefox profile and convert it to Base64 to save user screen preferences via `xulstore.json`. Addresses [#30300](https://github.com/cypress-io/cypress/issues/30300). ## 13.15.0 From 27bb8bd36c40595f0b5a50f327818d75c3c1ec3b Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Mon, 30 Sep 2024 18:37:27 -0400 Subject: [PATCH 04/22] chore: fix screenshot resolution [run ci] --- packages/server/lib/browsers/firefox.ts | 2 +- packages/server/test/unit/browsers/firefox_spec.ts | 4 ++-- system-tests/lib/pluginUtils.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/server/lib/browsers/firefox.ts b/packages/server/lib/browsers/firefox.ts index 8f1b18b7ca17..b41c5da17ab0 100644 --- a/packages/server/lib/browsers/firefox.ts +++ b/packages/server/lib/browsers/firefox.ts @@ -525,7 +525,7 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc const BROWSER_ENVS = { MOZ_REMOTE_SETTINGS_DEVTOOLS: '1', MOZ_HEADLESS_WIDTH: '1280', - MOZ_HEADLESS_HEIGHT: '806', + MOZ_HEADLESS_HEIGHT: '722', ...launchOptions.env, } diff --git a/packages/server/test/unit/browsers/firefox_spec.ts b/packages/server/test/unit/browsers/firefox_spec.ts index 7d95aaa0390b..2195ebd850e6 100644 --- a/packages/server/test/unit/browsers/firefox_spec.ts +++ b/packages/server/test/unit/browsers/firefox_spec.ts @@ -269,7 +269,7 @@ describe('lib/browsers/firefox', () => { env: { MOZ_REMOTE_SETTINGS_DEVTOOLS: '1', MOZ_HEADLESS_WIDTH: '1280', - MOZ_HEADLESS_HEIGHT: '806', + MOZ_HEADLESS_HEIGHT: '722', }, }), jsdebugger: false, @@ -334,7 +334,7 @@ describe('lib/browsers/firefox', () => { env: { MOZ_REMOTE_SETTINGS_DEVTOOLS: '1', MOZ_HEADLESS_WIDTH: '1280', - MOZ_HEADLESS_HEIGHT: '806', + MOZ_HEADLESS_HEIGHT: '722', }, }), jsdebugger: true, diff --git a/system-tests/lib/pluginUtils.js b/system-tests/lib/pluginUtils.js index b6f455e45647..618b0139acdf 100644 --- a/system-tests/lib/pluginUtils.js +++ b/system-tests/lib/pluginUtils.js @@ -8,7 +8,7 @@ module.exports = { // (height must account for firefox url bar, which we can only shrink to 1px , // and the total size of the window url and tab bar, which is 85 pixels for a total offset of 86 pixels) options.args.push( - '-width', '1280', '-height', '806', + '-width', '1280', '-height', '722', ) } else if (browser.name === 'electron') { options.preferences.width = 1280 From ff075cf081466875c67dafd9d0a5d1e673447085 Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Mon, 30 Sep 2024 19:33:15 -0400 Subject: [PATCH 05/22] fix check-ts issues [run ci] --- packages/data-context/src/DataContext.ts | 2 +- packages/frontend-shared/src/graphql/urqlFetchSocketAdapter.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/data-context/src/DataContext.ts b/packages/data-context/src/DataContext.ts index 3b4db97e276a..895dc4d12e4e 100644 --- a/packages/data-context/src/DataContext.ts +++ b/packages/data-context/src/DataContext.ts @@ -181,7 +181,7 @@ export class DataContext { @cached get cloud () { return new CloudDataSource({ - fetch: (...args) => this.util.fetch(...args), + fetch: (...args: [RequestInfo | URL, (RequestInit | undefined)?]) => this.util.fetch(...args), getUser: () => this.coreData.user, logout: () => this.actions.auth.logout().catch(this.logTraceError), invalidateClientUrqlCache: () => this.graphql.invalidateClientUrqlCache(this), diff --git a/packages/frontend-shared/src/graphql/urqlFetchSocketAdapter.ts b/packages/frontend-shared/src/graphql/urqlFetchSocketAdapter.ts index 1db4ac9f551b..c592434196e9 100644 --- a/packages/frontend-shared/src/graphql/urqlFetchSocketAdapter.ts +++ b/packages/frontend-shared/src/graphql/urqlFetchSocketAdapter.ts @@ -3,7 +3,7 @@ import type { SocketShape } from '@packages/socket/lib/types' import type { ClientOptions } from '@urql/core' export const urqlFetchSocketAdapter = (io: SocketShape): ClientOptions['fetch'] => { - return (url, fetchOptions = {}) => { + return (url, fetchOptions: RequestInit = {}) => { return new Promise((resolve, reject) => { // Handle aborted requests if (fetchOptions.signal) { From 31192bcc9d448187665bb78dbd9139920c95fa36 Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Mon, 30 Sep 2024 23:49:30 -0400 Subject: [PATCH 06/22] run windows ci [run ci] --- .circleci/workflows.yml | 2 +- cli/CHANGELOG.md | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.circleci/workflows.yml b/.circleci/workflows.yml index 302cff2ac35a..e02f7eeaac7a 100644 --- a/.circleci/workflows.yml +++ b/.circleci/workflows.yml @@ -76,7 +76,7 @@ windowsWorkflowFilters: &windows-workflow-filters - equal: [ develop, << pipeline.git.branch >> ] # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ] - - equal: [ 'misc/remove_marionette_for_geckodriver', << pipeline.git.branch >> ] + - equal: [ 'misc/use_webdriver', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index b7035f88c3cf..4af4409b8e22 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -6,8 +6,7 @@ _Released 10/1/2024 (PENDING)_ **Misc:** - Cypress now consumes [geckodriver](https://firefox-source-docs.mozilla.org/testing/geckodriver/index.html) to help automate the Firefox browser instead of [marionette-client](https://github.com/cypress-io/marionette-client). Addresses [#30217](https://github.com/cypress-io/cypress/issues/30217). -- Cypress now consumes [webdriver](https://github.com/webdriverio/webdriverio/tree/main/packages/webdriver) to help automate the Firefox browser. Addresses [#30301](https://github.com/cypress-io/cypress/issues/30301). -- Cypress now uses [firefox-profile](https://github.com/saadtazi/firefox-profile-js) to create a firefox profile and convert it to Base64 to save user screen preferences via `xulstore.json`. Addresses [#30300](https://github.com/cypress-io/cypress/issues/30300). +- Cypress now consumes [webdriver](https://github.com/webdriverio/webdriverio/tree/main/packages/webdriver) to help automate the Firefox browser and [firefox-profile](https://github.com/saadtazi/firefox-profile-js) to create a firefox profile and convert it to Base64 to save user screen preferences via `xulstore.json`. Addresses [#30300](https://github.com/cypress-io/cypress/issues/30300) and [#30301](https://github.com/cypress-io/cypress/issues/30301). ## 13.15.0 From 69b71961dca2b0d16e63a7d64186cda3b2b205a9 Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Mon, 30 Sep 2024 23:52:52 -0400 Subject: [PATCH 07/22] run ci From a937c506b1e92c84271680cdcd2ea7e490ed89d8 Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Tue, 1 Oct 2024 12:16:11 -0400 Subject: [PATCH 08/22] add comments [run ci] --- packages/server/lib/browsers/firefox.ts | 5 +++-- packages/server/patches/@wdio+protocols+9.0.0.patch | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/server/lib/browsers/firefox.ts b/packages/server/lib/browsers/firefox.ts index b41c5da17ab0..c2998219c3d6 100644 --- a/packages/server/lib/browsers/firefox.ts +++ b/packages/server/lib/browsers/firefox.ts @@ -607,8 +607,9 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc const WD = WebDriver.getWebDriverPackage() // this command starts the webdriver session and actually opens the browser - // to debug geckodriver, set the DEBUG=cypress-verbose:server:browsers:geckodriver (debugs a third-party patched package geckodriver) - // @see ./WEB_DRIVER.md + // to debug geckodriver, set the DEBUG=cypress-verbose:server:browsers:geckodriver (debugs a third-party patched package geckodriver to enable console output) + // to debug webdriver, set the DEBUG=cypress-verbose:server:browsers:webdriver (debugs a third-party patched package webdriver to enable console output) + // @see ./firefox_automation.md const webdriverClient = await WD.newSession(newSessionCapabilities) debugVerbose(`received capabilities %o`, webdriverClient.capabilities) diff --git a/packages/server/patches/@wdio+protocols+9.0.0.patch b/packages/server/patches/@wdio+protocols+9.0.0.patch index 840928bb1716..f07bd7459da8 100644 --- a/packages/server/patches/@wdio+protocols+9.0.0.patch +++ b/packages/server/patches/@wdio+protocols+9.0.0.patch @@ -73,7 +73,7 @@ index 05e55cc..9ea546e 100644 + name: "path", type: "string", - description: "base64 string of the add on file", -+ description: "string of the add on file", ++ description: "path to the extension", required: true }, { From 5809c5f2bd13c9e1979da9ee2961cafedb478da6 Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Wed, 2 Oct 2024 12:10:42 -0400 Subject: [PATCH 09/22] build binaries for webdriver impl [run ci] --- .circleci/workflows.yml | 8 ++++---- packages/server/lib/browsers/firefox.ts | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.circleci/workflows.yml b/.circleci/workflows.yml index e02f7eeaac7a..370f7d1cb5a0 100644 --- a/.circleci/workflows.yml +++ b/.circleci/workflows.yml @@ -30,7 +30,7 @@ mainBuildFilters: &mainBuildFilters - /^release\/\d+\.\d+\.\d+$/ # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - 'update-v8-snapshot-cache-on-develop' - - 'misc/remove_marionette_for_geckodriver' + - 'misc/use_webdriver' - 'publish-binary' # usually we don't build Mac app - it takes a long time @@ -42,7 +42,7 @@ macWorkflowFilters: &darwin-workflow-filters - equal: [ develop, << pipeline.git.branch >> ] # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ] - - equal: [ 'misc/remove_marionette_for_geckodriver', << pipeline.git.branch >> ] + - equal: [ 'misc/use_webdriver', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -53,7 +53,7 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters - equal: [ develop, << pipeline.git.branch >> ] # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ] - - equal: [ 'misc/remove_marionette_for_geckodriver', << pipeline.git.branch >> ] + - equal: [ 'misc/use_webdriver', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -152,7 +152,7 @@ commands: name: Set environment variable to determine whether or not to persist artifacts command: | echo "Setting SHOULD_PERSIST_ARTIFACTS variable" - echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "misc/remove_marionette_for_geckodriver" ]]; then + echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "misc/use_webdriver" ]]; then export SHOULD_PERSIST_ARTIFACTS=true fi' >> "$BASH_ENV" # You must run `setup_should_persist_artifacts` command and be using bash before running this command diff --git a/packages/server/lib/browsers/firefox.ts b/packages/server/lib/browsers/firefox.ts index c2998219c3d6..5a4e55506b05 100644 --- a/packages/server/lib/browsers/firefox.ts +++ b/packages/server/lib/browsers/firefox.ts @@ -591,6 +591,7 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc // @ts-expect-error 'moz:debuggerAddress': true, // @see https://webdriver.io/docs/capabilities/#wdiogeckodriveroptions + // webdriver starts geckodriver with the correct options on behalf of Cypress 'wdio:geckodriverOptions': geckoDriverOptions, }, firstMatch: [], From 4f3804d7d94e5e2b0b54e6c7ef8ae4209aa3f298 Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Mon, 7 Oct 2024 11:02:44 -0400 Subject: [PATCH 10/22] fix Cypress namespace missing issue. see https://github.com/cypress-io/cypress/pull/30331/commits/6d7ba97c2562054e11983e8bfed576f0fa3ee37b --- packages/types/src/spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/types/src/spec.ts b/packages/types/src/spec.ts index 1725e6723c24..8003d2c2b6ff 100644 --- a/packages/types/src/spec.ts +++ b/packages/types/src/spec.ts @@ -13,7 +13,8 @@ export interface SpecFile extends BaseSpec { export interface FoundSpec extends SpecFile { specFileExtension: string fileExtension: string - specType: Cypress.CypressSpecType + // see: ./cli/types/cypress.d.ts `Cypress.CypressSpecType` + specType: 'integration' | 'component' } export interface SpecWithRelativeRoot extends FoundSpec { From 68f50a21dab9361e3fe95c1e220ef1dac1f95a1c Mon Sep 17 00:00:00 2001 From: "cypress-bot[bot]" <+cypress-bot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 19:37:46 +0000 Subject: [PATCH 11/22] chore: updating v8 snapshot cache --- .../cache/linux/snapshot-meta.json | 104 ++++++------------ 1 file changed, 35 insertions(+), 69 deletions(-) diff --git a/tooling/v8-snapshot/cache/linux/snapshot-meta.json b/tooling/v8-snapshot/cache/linux/snapshot-meta.json index 3de9bf87eb70..9bc216ba0bc2 100644 --- a/tooling/v8-snapshot/cache/linux/snapshot-meta.json +++ b/tooling/v8-snapshot/cache/linux/snapshot-meta.json @@ -225,9 +225,6 @@ "./node_modules/async/dist/async.js", "./node_modules/basic-auth/node_modules/safe-buffer/index.js", "./node_modules/black-hole-stream/index.js", - "./node_modules/body-parser/index.js", - "./node_modules/body-parser/node_modules/debug/src/browser.js", - "./node_modules/body-parser/node_modules/debug/src/index.js", "./node_modules/buffer-from/index.js", "./node_modules/chalk/index.js", "./node_modules/chrome-remote-interface/index.js", @@ -270,19 +267,9 @@ "./node_modules/express-graphql/node_modules/depd/index.js", "./node_modules/express-graphql/node_modules/http-errors/index.js", "./node_modules/express-graphql/parseBody.js", - "./node_modules/express/lib/application.js", - "./node_modules/express/lib/request.js", - "./node_modules/express/lib/response.js", - "./node_modules/express/lib/router/index.js", - "./node_modules/express/lib/router/route.js", - "./node_modules/express/node_modules/debug/src/browser.js", - "./node_modules/express/node_modules/debug/src/index.js", - "./node_modules/express/node_modules/send/index.js", "./node_modules/fast-glob/out/settings.js", "./node_modules/fast-glob/out/utils/path.js", "./node_modules/file-uri-to-path/index.js", - "./node_modules/finalhandler/node_modules/debug/src/browser.js", - "./node_modules/finalhandler/node_modules/debug/src/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/fs/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/json/index.js", @@ -343,8 +330,6 @@ "./node_modules/lodash/isBuffer.js", "./node_modules/lodash/lodash.js", "./node_modules/make-dir/node_modules/semver/semver.js", - "./node_modules/marionette-client/lib/marionette/index.js", - "./node_modules/marionette-client/lib/marionette/marionette.js", "./node_modules/methods/index.js", "./node_modules/mime/mime.js", "./node_modules/mocha-7.0.1/index.js", @@ -521,10 +506,6 @@ "./node_modules/send/index.js", "./node_modules/send/node_modules/debug/src/browser.js", "./node_modules/send/node_modules/debug/src/index.js", - "./node_modules/serve-static/node_modules/debug/src/browser.js", - "./node_modules/serve-static/node_modules/debug/src/index.js", - "./node_modules/serve-static/node_modules/debug/src/node.js", - "./node_modules/serve-static/node_modules/send/index.js", "./node_modules/shell-env/node_modules/execa/lib/errname.js", "./node_modules/shell-env/node_modules/get-stream/buffer-stream.js", "./node_modules/shell-env/node_modules/semver/semver.js", @@ -666,11 +647,16 @@ "./packages/errors/index.js", "./packages/errors/src/errTemplate.ts", "./packages/graphql/index.js", + "./packages/graphql/node_modules/body-parser/index.js", "./packages/graphql/node_modules/chalk/node_modules/supports-color/index.js", "./packages/graphql/node_modules/chalk/source/index.js", "./packages/graphql/node_modules/debug/src/browser.js", "./packages/graphql/node_modules/debug/src/index.js", - "./packages/graphql/node_modules/supports-color/index.js", + "./packages/graphql/node_modules/express/lib/application.js", + "./packages/graphql/node_modules/express/lib/request.js", + "./packages/graphql/node_modules/express/lib/response.js", + "./packages/graphql/node_modules/express/lib/router/index.js", + "./packages/graphql/node_modules/express/lib/router/route.js", "./packages/graphql/src/makeGraphQLServer.ts", "./packages/graphql/src/plugins/index.ts", "./packages/graphql/src/plugins/nexusDebugFieldPlugin.ts", @@ -1590,18 +1576,6 @@ "./node_modules/binary-extensions/index.js", "./node_modules/binaryextensions/edition-es5/index.js", "./node_modules/bindings/bindings.js", - "./node_modules/body-parser/lib/read.js", - "./node_modules/body-parser/lib/types/json.js", - "./node_modules/body-parser/lib/types/raw.js", - "./node_modules/body-parser/lib/types/text.js", - "./node_modules/body-parser/lib/types/urlencoded.js", - "./node_modules/body-parser/node_modules/debug/src/debug.js", - "./node_modules/body-parser/node_modules/ms/index.js", - "./node_modules/body-parser/node_modules/qs/lib/formats.js", - "./node_modules/body-parser/node_modules/qs/lib/index.js", - "./node_modules/body-parser/node_modules/qs/lib/parse.js", - "./node_modules/body-parser/node_modules/qs/lib/stringify.js", - "./node_modules/body-parser/node_modules/qs/lib/utils.js", "./node_modules/braces/index.js", "./node_modules/braces/lib/compile.js", "./node_modules/braces/lib/constants.js", @@ -1760,7 +1734,6 @@ "./node_modules/dayjs/plugin/duration.js", "./node_modules/dayjs/plugin/relativeTime.js", "./node_modules/dayjs/plugin/updateLocale.js", - "./node_modules/debug/node_modules/ms/index.js", "./node_modules/debug/src/common.js", "./node_modules/dedent/dist/dedent.js", "./node_modules/deep-is/index.js", @@ -1860,24 +1833,6 @@ "./node_modules/express-graphql/node_modules/statuses/index.js", "./node_modules/express-graphql/node_modules/toidentifier/index.js", "./node_modules/express-graphql/renderGraphiQL.js", - "./node_modules/express/index.js", - "./node_modules/express/lib/express.js", - "./node_modules/express/lib/middleware/init.js", - "./node_modules/express/lib/middleware/query.js", - "./node_modules/express/lib/router/layer.js", - "./node_modules/express/lib/utils.js", - "./node_modules/express/lib/view.js", - "./node_modules/express/node_modules/cookie/index.js", - "./node_modules/express/node_modules/debug/src/debug.js", - "./node_modules/express/node_modules/merge-descriptors/index.js", - "./node_modules/express/node_modules/ms/index.js", - "./node_modules/express/node_modules/path-to-regexp/index.js", - "./node_modules/express/node_modules/qs/lib/formats.js", - "./node_modules/express/node_modules/qs/lib/index.js", - "./node_modules/express/node_modules/qs/lib/parse.js", - "./node_modules/express/node_modules/qs/lib/stringify.js", - "./node_modules/express/node_modules/qs/lib/utils.js", - "./node_modules/express/node_modules/send/node_modules/ms/index.js", "./node_modules/ext-list/index.js", "./node_modules/ext-name/index.js", "./node_modules/extend/index.js", @@ -1907,9 +1862,6 @@ "./node_modules/fast-glob/out/utils/string.js", "./node_modules/fastq/queue.js", "./node_modules/fill-range/index.js", - "./node_modules/finalhandler/index.js", - "./node_modules/finalhandler/node_modules/debug/src/debug.js", - "./node_modules/finalhandler/node_modules/ms/index.js", "./node_modules/find-process/index.js", "./node_modules/find-process/lib/find.js", "./node_modules/find-process/lib/find_pid.js", @@ -1917,8 +1869,7 @@ "./node_modules/find-process/lib/utils.js", "./node_modules/firefox-profile/lib/firefox_profile.js", "./node_modules/firefox-profile/lib/profile_finder.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy-sync/copy-sync.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy-sync/index.js", + "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy/copy-sync.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy/copy.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/empty/index.js", @@ -1932,17 +1883,15 @@ "./node_modules/firefox-profile/node_modules/fs-extra/lib/json/output-json.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/mkdirs/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/mkdirs/make-dir.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/move-sync/index.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/move-sync/move-sync.js", + "./node_modules/firefox-profile/node_modules/fs-extra/lib/mkdirs/utils.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/move/index.js", + "./node_modules/firefox-profile/node_modules/fs-extra/lib/move/move-sync.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/move/move.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/output/index.js", + "./node_modules/firefox-profile/node_modules/fs-extra/lib/output-file/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/remove/index.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/remove/rimraf.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/util/stat.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/util/utimes.js", - "./node_modules/firefox-profile/node_modules/ini/ini.js", - "./node_modules/firefox-profile/node_modules/jsonfile/node_modules/universalify/index.js", + "./node_modules/firefox-profile/node_modules/ini/lib/ini.js", "./node_modules/firefox-profile/node_modules/jsonfile/utils.js", "./node_modules/firefox-profile/node_modules/universalify/index.js", "./node_modules/fluent-ffmpeg/lib/capabilities.js", @@ -2493,7 +2442,6 @@ "./node_modules/lodash/toString.js", "./node_modules/make-dir/node_modules/pify/index.js", "./node_modules/make-error/index.js", - "./node_modules/marionette-client/lib/marionette/message.js", "./node_modules/md5/md5.js", "./node_modules/media-typer/index.js", "./node_modules/merge-descriptors/index.js", @@ -3310,9 +3258,6 @@ "./node_modules/semver/ranges/valid.js", "./node_modules/send/node_modules/debug/node_modules/ms/index.js", "./node_modules/send/node_modules/debug/src/debug.js", - "./node_modules/serve-static/index.js", - "./node_modules/serve-static/node_modules/debug/node_modules/ms/index.js", - "./node_modules/serve-static/node_modules/debug/src/debug.js", "./node_modules/server-destroy/index.js", "./node_modules/set-function-length/index.js", "./node_modules/setprototypeof/index.js", @@ -3443,7 +3388,6 @@ "./node_modules/trash/node_modules/uuid/lib/rng.js", "./node_modules/trash/node_modules/uuid/v1.js", "./node_modules/trash/node_modules/uuid/v4.js", - "./node_modules/tree-kill/index.js", "./node_modules/truncate-utf8-bytes/lib/truncate.js", "./node_modules/ts-node/dist-raw/node-internal-constants.js", "./node_modules/ts-node/dist-raw/node-internal-errors.js", @@ -3848,10 +3792,28 @@ "./packages/extension/lib/util.js", "./packages/frontend-shared/cypress/e2e/prod-dependencies.ts", "./packages/frontend-shared/cypress/e2e/v8-snapshot-entry.ts", + "./packages/graphql/node_modules/body-parser/lib/read.js", + "./packages/graphql/node_modules/body-parser/lib/types/json.js", + "./packages/graphql/node_modules/body-parser/lib/types/raw.js", + "./packages/graphql/node_modules/body-parser/lib/types/text.js", + "./packages/graphql/node_modules/body-parser/lib/types/urlencoded.js", "./packages/graphql/node_modules/chalk/source/templates.js", "./packages/graphql/node_modules/chalk/source/util.js", - "./packages/graphql/node_modules/debug/src/common.js", + "./packages/graphql/node_modules/cookie/index.js", + "./packages/graphql/node_modules/debug/node_modules/ms/index.js", + "./packages/graphql/node_modules/debug/src/debug.js", + "./packages/graphql/node_modules/encodeurl/index.js", + "./packages/graphql/node_modules/express/index.js", + "./packages/graphql/node_modules/express/lib/express.js", + "./packages/graphql/node_modules/express/lib/middleware/init.js", + "./packages/graphql/node_modules/express/lib/middleware/query.js", + "./packages/graphql/node_modules/express/lib/router/layer.js", + "./packages/graphql/node_modules/express/lib/utils.js", + "./packages/graphql/node_modules/express/lib/view.js", + "./packages/graphql/node_modules/finalhandler/index.js", "./packages/graphql/node_modules/has-flag/index.js", + "./packages/graphql/node_modules/path-to-regexp/index.js", + "./packages/graphql/node_modules/serve-static/index.js", "./packages/graphql/src/index.ts", "./packages/https-proxy/lib/proxy.js", "./packages/https-proxy/lib/server.js", @@ -3981,11 +3943,13 @@ "./packages/server/lib/browsers/memory/cgroup-v1.ts", "./packages/server/lib/browsers/memory/default.ts", "./packages/server/lib/browsers/protocol.ts", + "./packages/server/lib/browsers/webdriver/index.ts", "./packages/server/lib/browsers/webkit-automation.ts", "./packages/server/lib/browsers/webkit.ts", "./packages/server/lib/cloud/api/scrub_url.ts", "./packages/server/lib/cloud/artifacts/artifact.ts", "./packages/server/lib/cloud/artifacts/file_upload_strategy.ts", + "./packages/server/lib/cloud/artifacts/print_protocol_upload_error.ts", "./packages/server/lib/cloud/artifacts/upload_artifacts.ts", "./packages/server/lib/cloud/encryption.ts", "./packages/server/lib/cloud/environment.ts", @@ -3998,6 +3962,7 @@ "./packages/server/lib/cloud/protocol.ts", "./packages/server/lib/cloud/upload/send_file.ts", "./packages/server/lib/cloud/upload/stream_activity_monitor.ts", + "./packages/server/lib/cloud/upload/stream_stalled_error.ts", "./packages/server/lib/cohorts.ts", "./packages/server/lib/controllers/client.js", "./packages/server/lib/controllers/files.js", @@ -4208,6 +4173,7 @@ "./packages/server/node_modules/p-queue/dist/priority-queue.js", "./packages/server/node_modules/path-key/index.js", "./packages/server/node_modules/path-to-regexp/index.js", + "./packages/server/node_modules/pump/index.js", "./packages/server/node_modules/readable-stream/lib/internal/streams/async_iterator.js", "./packages/server/node_modules/readable-stream/lib/internal/streams/destroy.js", "./packages/server/node_modules/readable-stream/lib/internal/streams/end-of-stream.js", @@ -4270,5 +4236,5 @@ "./tooling/v8-snapshot/cache/linux/snapshot-entry.js" ], "deferredHashFile": "yarn.lock", - "deferredHash": "9ab51832162435dec2de359d222b063dfdce4b3d555581562e6f2c4255bc1e9b" + "deferredHash": "4c1da762a851baab24ef5d1ba9d878ad207147c7703383f4796c0c9c7910240f" } \ No newline at end of file From 6f33c60a8b5265ad53023fc7058e374e6723a439 Mon Sep 17 00:00:00 2001 From: "cypress-bot[bot]" <+cypress-bot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 20:33:57 +0000 Subject: [PATCH 12/22] chore: updating v8 snapshot cache --- tooling/v8-snapshot/cache/darwin/snapshot-meta.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/v8-snapshot/cache/darwin/snapshot-meta.json b/tooling/v8-snapshot/cache/darwin/snapshot-meta.json index 1b82f1ce43f7..aee9bac711d4 100644 --- a/tooling/v8-snapshot/cache/darwin/snapshot-meta.json +++ b/tooling/v8-snapshot/cache/darwin/snapshot-meta.json @@ -4237,5 +4237,5 @@ "./tooling/v8-snapshot/cache/darwin/snapshot-entry.js" ], "deferredHashFile": "yarn.lock", - "deferredHash": "7186aa2740a0751567e15f6fb7493ba7ae01f37845157c0fa91257bee987a635" + "deferredHash": "4c1da762a851baab24ef5d1ba9d878ad207147c7703383f4796c0c9c7910240f" } \ No newline at end of file From c17f87c2523aec4960727d9d3589744d1fd14481 Mon Sep 17 00:00:00 2001 From: "cypress-bot[bot]" <+cypress-bot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 22:10:29 +0000 Subject: [PATCH 13/22] chore: updating v8 snapshot cache --- .../cache/win32/snapshot-meta.json | 104 ++++++------------ 1 file changed, 35 insertions(+), 69 deletions(-) diff --git a/tooling/v8-snapshot/cache/win32/snapshot-meta.json b/tooling/v8-snapshot/cache/win32/snapshot-meta.json index bee31a50c414..6176f11d7a00 100644 --- a/tooling/v8-snapshot/cache/win32/snapshot-meta.json +++ b/tooling/v8-snapshot/cache/win32/snapshot-meta.json @@ -224,9 +224,6 @@ "./node_modules/async/dist/async.js", "./node_modules/basic-auth/node_modules/safe-buffer/index.js", "./node_modules/black-hole-stream/index.js", - "./node_modules/body-parser/index.js", - "./node_modules/body-parser/node_modules/debug/src/browser.js", - "./node_modules/body-parser/node_modules/debug/src/index.js", "./node_modules/buffer-from/index.js", "./node_modules/chalk/index.js", "./node_modules/chrome-remote-interface/index.js", @@ -269,19 +266,9 @@ "./node_modules/express-graphql/node_modules/depd/index.js", "./node_modules/express-graphql/node_modules/http-errors/index.js", "./node_modules/express-graphql/parseBody.js", - "./node_modules/express/lib/application.js", - "./node_modules/express/lib/request.js", - "./node_modules/express/lib/response.js", - "./node_modules/express/lib/router/index.js", - "./node_modules/express/lib/router/route.js", - "./node_modules/express/node_modules/debug/src/browser.js", - "./node_modules/express/node_modules/debug/src/index.js", - "./node_modules/express/node_modules/send/index.js", "./node_modules/fast-glob/out/settings.js", "./node_modules/fast-glob/out/utils/path.js", "./node_modules/file-uri-to-path/index.js", - "./node_modules/finalhandler/node_modules/debug/src/browser.js", - "./node_modules/finalhandler/node_modules/debug/src/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/fs/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/json/index.js", @@ -342,8 +329,6 @@ "./node_modules/lodash/isBuffer.js", "./node_modules/lodash/lodash.js", "./node_modules/make-dir/node_modules/semver/semver.js", - "./node_modules/marionette-client/lib/marionette/index.js", - "./node_modules/marionette-client/lib/marionette/marionette.js", "./node_modules/methods/index.js", "./node_modules/mime/mime.js", "./node_modules/mocha-7.0.1/index.js", @@ -521,10 +506,6 @@ "./node_modules/send/index.js", "./node_modules/send/node_modules/debug/src/browser.js", "./node_modules/send/node_modules/debug/src/index.js", - "./node_modules/serve-static/node_modules/debug/src/browser.js", - "./node_modules/serve-static/node_modules/debug/src/index.js", - "./node_modules/serve-static/node_modules/debug/src/node.js", - "./node_modules/serve-static/node_modules/send/index.js", "./node_modules/shell-env/node_modules/execa/lib/errname.js", "./node_modules/shell-env/node_modules/get-stream/buffer-stream.js", "./node_modules/shell-env/node_modules/semver/semver.js", @@ -668,11 +649,16 @@ "./packages/errors/index.js", "./packages/errors/src/errTemplate.ts", "./packages/graphql/index.js", + "./packages/graphql/node_modules/body-parser/index.js", "./packages/graphql/node_modules/chalk/node_modules/supports-color/index.js", "./packages/graphql/node_modules/chalk/source/index.js", "./packages/graphql/node_modules/debug/src/browser.js", "./packages/graphql/node_modules/debug/src/index.js", - "./packages/graphql/node_modules/supports-color/index.js", + "./packages/graphql/node_modules/express/lib/application.js", + "./packages/graphql/node_modules/express/lib/request.js", + "./packages/graphql/node_modules/express/lib/response.js", + "./packages/graphql/node_modules/express/lib/router/index.js", + "./packages/graphql/node_modules/express/lib/router/route.js", "./packages/graphql/src/makeGraphQLServer.ts", "./packages/graphql/src/plugins/index.ts", "./packages/graphql/src/plugins/nexusDebugFieldPlugin.ts", @@ -1593,18 +1579,6 @@ "./node_modules/binary-extensions/index.js", "./node_modules/binaryextensions/edition-es5/index.js", "./node_modules/bindings/bindings.js", - "./node_modules/body-parser/lib/read.js", - "./node_modules/body-parser/lib/types/json.js", - "./node_modules/body-parser/lib/types/raw.js", - "./node_modules/body-parser/lib/types/text.js", - "./node_modules/body-parser/lib/types/urlencoded.js", - "./node_modules/body-parser/node_modules/debug/src/debug.js", - "./node_modules/body-parser/node_modules/ms/index.js", - "./node_modules/body-parser/node_modules/qs/lib/formats.js", - "./node_modules/body-parser/node_modules/qs/lib/index.js", - "./node_modules/body-parser/node_modules/qs/lib/parse.js", - "./node_modules/body-parser/node_modules/qs/lib/stringify.js", - "./node_modules/body-parser/node_modules/qs/lib/utils.js", "./node_modules/braces/index.js", "./node_modules/braces/lib/compile.js", "./node_modules/braces/lib/constants.js", @@ -1763,7 +1737,6 @@ "./node_modules/dayjs/plugin/duration.js", "./node_modules/dayjs/plugin/relativeTime.js", "./node_modules/dayjs/plugin/updateLocale.js", - "./node_modules/debug/node_modules/ms/index.js", "./node_modules/debug/src/common.js", "./node_modules/dedent/dist/dedent.js", "./node_modules/deep-is/index.js", @@ -1863,24 +1836,6 @@ "./node_modules/express-graphql/node_modules/statuses/index.js", "./node_modules/express-graphql/node_modules/toidentifier/index.js", "./node_modules/express-graphql/renderGraphiQL.js", - "./node_modules/express/index.js", - "./node_modules/express/lib/express.js", - "./node_modules/express/lib/middleware/init.js", - "./node_modules/express/lib/middleware/query.js", - "./node_modules/express/lib/router/layer.js", - "./node_modules/express/lib/utils.js", - "./node_modules/express/lib/view.js", - "./node_modules/express/node_modules/cookie/index.js", - "./node_modules/express/node_modules/debug/src/debug.js", - "./node_modules/express/node_modules/merge-descriptors/index.js", - "./node_modules/express/node_modules/ms/index.js", - "./node_modules/express/node_modules/path-to-regexp/index.js", - "./node_modules/express/node_modules/qs/lib/formats.js", - "./node_modules/express/node_modules/qs/lib/index.js", - "./node_modules/express/node_modules/qs/lib/parse.js", - "./node_modules/express/node_modules/qs/lib/stringify.js", - "./node_modules/express/node_modules/qs/lib/utils.js", - "./node_modules/express/node_modules/send/node_modules/ms/index.js", "./node_modules/ext-list/index.js", "./node_modules/ext-name/index.js", "./node_modules/extend/index.js", @@ -1910,9 +1865,6 @@ "./node_modules/fast-glob/out/utils/string.js", "./node_modules/fastq/queue.js", "./node_modules/fill-range/index.js", - "./node_modules/finalhandler/index.js", - "./node_modules/finalhandler/node_modules/debug/src/debug.js", - "./node_modules/finalhandler/node_modules/ms/index.js", "./node_modules/find-process/index.js", "./node_modules/find-process/lib/find.js", "./node_modules/find-process/lib/find_pid.js", @@ -1920,8 +1872,7 @@ "./node_modules/find-process/lib/utils.js", "./node_modules/firefox-profile/lib/firefox_profile.js", "./node_modules/firefox-profile/lib/profile_finder.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy-sync/copy-sync.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy-sync/index.js", + "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy/copy-sync.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy/copy.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/copy/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/empty/index.js", @@ -1935,17 +1886,15 @@ "./node_modules/firefox-profile/node_modules/fs-extra/lib/json/output-json.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/mkdirs/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/mkdirs/make-dir.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/move-sync/index.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/move-sync/move-sync.js", + "./node_modules/firefox-profile/node_modules/fs-extra/lib/mkdirs/utils.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/move/index.js", + "./node_modules/firefox-profile/node_modules/fs-extra/lib/move/move-sync.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/move/move.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/output/index.js", + "./node_modules/firefox-profile/node_modules/fs-extra/lib/output-file/index.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/remove/index.js", - "./node_modules/firefox-profile/node_modules/fs-extra/lib/remove/rimraf.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/util/stat.js", "./node_modules/firefox-profile/node_modules/fs-extra/lib/util/utimes.js", - "./node_modules/firefox-profile/node_modules/ini/ini.js", - "./node_modules/firefox-profile/node_modules/jsonfile/node_modules/universalify/index.js", + "./node_modules/firefox-profile/node_modules/ini/lib/ini.js", "./node_modules/firefox-profile/node_modules/jsonfile/utils.js", "./node_modules/firefox-profile/node_modules/universalify/index.js", "./node_modules/fluent-ffmpeg/lib/capabilities.js", @@ -2496,7 +2445,6 @@ "./node_modules/lodash/toString.js", "./node_modules/make-dir/node_modules/pify/index.js", "./node_modules/make-error/index.js", - "./node_modules/marionette-client/lib/marionette/message.js", "./node_modules/md5/md5.js", "./node_modules/media-typer/index.js", "./node_modules/merge-descriptors/index.js", @@ -3312,9 +3260,6 @@ "./node_modules/semver/ranges/valid.js", "./node_modules/send/node_modules/debug/node_modules/ms/index.js", "./node_modules/send/node_modules/debug/src/debug.js", - "./node_modules/serve-static/index.js", - "./node_modules/serve-static/node_modules/debug/node_modules/ms/index.js", - "./node_modules/serve-static/node_modules/debug/src/debug.js", "./node_modules/server-destroy/index.js", "./node_modules/set-function-length/index.js", "./node_modules/setprototypeof/index.js", @@ -3444,7 +3389,6 @@ "./node_modules/trash/node_modules/uuid/lib/rng.js", "./node_modules/trash/node_modules/uuid/v1.js", "./node_modules/trash/node_modules/uuid/v4.js", - "./node_modules/tree-kill/index.js", "./node_modules/truncate-utf8-bytes/lib/truncate.js", "./node_modules/ts-node/dist-raw/node-internal-constants.js", "./node_modules/ts-node/dist-raw/node-internal-errors.js", @@ -3848,10 +3792,28 @@ "./packages/extension/lib/util.js", "./packages/frontend-shared/cypress/e2e/prod-dependencies.ts", "./packages/frontend-shared/cypress/e2e/v8-snapshot-entry.ts", + "./packages/graphql/node_modules/body-parser/lib/read.js", + "./packages/graphql/node_modules/body-parser/lib/types/json.js", + "./packages/graphql/node_modules/body-parser/lib/types/raw.js", + "./packages/graphql/node_modules/body-parser/lib/types/text.js", + "./packages/graphql/node_modules/body-parser/lib/types/urlencoded.js", "./packages/graphql/node_modules/chalk/source/templates.js", "./packages/graphql/node_modules/chalk/source/util.js", - "./packages/graphql/node_modules/debug/src/common.js", + "./packages/graphql/node_modules/cookie/index.js", + "./packages/graphql/node_modules/debug/node_modules/ms/index.js", + "./packages/graphql/node_modules/debug/src/debug.js", + "./packages/graphql/node_modules/encodeurl/index.js", + "./packages/graphql/node_modules/express/index.js", + "./packages/graphql/node_modules/express/lib/express.js", + "./packages/graphql/node_modules/express/lib/middleware/init.js", + "./packages/graphql/node_modules/express/lib/middleware/query.js", + "./packages/graphql/node_modules/express/lib/router/layer.js", + "./packages/graphql/node_modules/express/lib/utils.js", + "./packages/graphql/node_modules/express/lib/view.js", + "./packages/graphql/node_modules/finalhandler/index.js", "./packages/graphql/node_modules/has-flag/index.js", + "./packages/graphql/node_modules/path-to-regexp/index.js", + "./packages/graphql/node_modules/serve-static/index.js", "./packages/graphql/src/index.ts", "./packages/https-proxy/lib/proxy.js", "./packages/https-proxy/lib/server.js", @@ -3981,11 +3943,13 @@ "./packages/server/lib/browsers/memory/cgroup-v1.ts", "./packages/server/lib/browsers/memory/default.ts", "./packages/server/lib/browsers/protocol.ts", + "./packages/server/lib/browsers/webdriver/index.ts", "./packages/server/lib/browsers/webkit-automation.ts", "./packages/server/lib/browsers/webkit.ts", "./packages/server/lib/cloud/api/scrub_url.ts", "./packages/server/lib/cloud/artifacts/artifact.ts", "./packages/server/lib/cloud/artifacts/file_upload_strategy.ts", + "./packages/server/lib/cloud/artifacts/print_protocol_upload_error.ts", "./packages/server/lib/cloud/artifacts/upload_artifacts.ts", "./packages/server/lib/cloud/encryption.ts", "./packages/server/lib/cloud/environment.ts", @@ -3998,6 +3962,7 @@ "./packages/server/lib/cloud/protocol.ts", "./packages/server/lib/cloud/upload/send_file.ts", "./packages/server/lib/cloud/upload/stream_activity_monitor.ts", + "./packages/server/lib/cloud/upload/stream_stalled_error.ts", "./packages/server/lib/cohorts.ts", "./packages/server/lib/controllers/client.js", "./packages/server/lib/controllers/files.js", @@ -4208,6 +4173,7 @@ "./packages/server/node_modules/p-queue/dist/priority-queue.js", "./packages/server/node_modules/path-key/index.js", "./packages/server/node_modules/path-to-regexp/index.js", + "./packages/server/node_modules/pump/index.js", "./packages/server/node_modules/readable-stream/lib/internal/streams/async_iterator.js", "./packages/server/node_modules/readable-stream/lib/internal/streams/destroy.js", "./packages/server/node_modules/readable-stream/lib/internal/streams/end-of-stream.js", @@ -4270,5 +4236,5 @@ "./tooling/v8-snapshot/cache/win32/snapshot-entry.js" ], "deferredHashFile": "yarn.lock", - "deferredHash": "f18ec1dec107c1830ca781417585733b0b6bd4ab18c20910588f5e7bf4de40fb" + "deferredHash": "13b4e2c024574673089f0bd15e763cc1db73256cafb63a98edb1e916317e3d3f" } \ No newline at end of file From 9f647f9703ca1204dda11d97289b0bfce1a21107 Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Mon, 7 Oct 2024 19:11:03 -0400 Subject: [PATCH 14/22] patch edgedriver and preserve dependency paths for webdriver so they are included in the binary [run ci] --- .circleci/cache-version.txt | 2 +- .../server/lib/browsers/firefox_automation.md | 2 +- packages/server/package.json | 4 +- .../server/patches/edgedriver+5.6.1.patch | 237 ++++++++++++++++++ scripts/binary/binary-cleanup.js | 1 + yarn.lock | 4 +- 6 files changed, 244 insertions(+), 6 deletions(-) create mode 100644 packages/server/patches/edgedriver+5.6.1.patch diff --git a/.circleci/cache-version.txt b/.circleci/cache-version.txt index 36169ec4edd4..4bb51c5873a8 100644 --- a/.circleci/cache-version.txt +++ b/.circleci/cache-version.txt @@ -1,3 +1,3 @@ # Bump this version to force CI to re-create the cache from scratch. -10-07-24 +10-08-24-webdriver2 diff --git a/packages/server/lib/browsers/firefox_automation.md b/packages/server/lib/browsers/firefox_automation.md index 342848c01989..0c7e57222fe7 100644 --- a/packages/server/lib/browsers/firefox_automation.md +++ b/packages/server/lib/browsers/firefox_automation.md @@ -27,7 +27,7 @@ It is worth noting that Cypress patches the [`geckodriver`](https://github.com/w Currently, the use of WebDriver Classic is small. To prepare for the implementation of WebDriver BiDi and reduce the need for maintenance code, the methods are implemented via the [webdriver](https://github.com/webdriverio/webdriverio/tree/main/packages/webdriver) package. It's important to note that, unlike Chrome, Firefox is launched via the WebDriver [newSession command](https://w3c.github.io/webdriver#new-session) (via `webdriver` [package](https://github.com/webdriverio/webdriverio/tree/main/packages/webdriver#webdriver-example)). -Since we patch the [`geckodriver`](https://github.com/webdriverio-community/node-geckodriver#readme) and the related [`webdriver`](https://github.com/webdriverio/webdriverio/tree/main/packages) packages, we [`nohoist`](https://classic.yarnpkg.com/blog/2018/02/15/nohoist/) the dependencies. This mostly works with sub-dependencies, but one of the dependencies, `pump@^3.0.0` (from `geckodriver` -> `tar-fs` -> `pump`) is missing from the binary. To workaround this, we install `pump` in `@packages/server` and `nohoist` the dependency so it is available in the binary as a production dependency. +Since we patch the [`geckodriver`](https://github.com/webdriverio-community/node-geckodriver#readme) and the related [`webdriver`](https://github.com/webdriverio/webdriverio/tree/main/packages) packages, we [`nohoist`](https://classic.yarnpkg.com/blog/2018/02/15/nohoist/) the dependencies. We keep all dependencies related to `webdriver` in the packherd `binary-cleanup` file. One of these preserved dependencies, `edgedriver@5.6.1` has the same top-level await that `geckodriver` uses, so we need to patch it. We do not consume this package directly. This is just to make sure the binary can build. ## Debugging diff --git a/packages/server/package.json b/packages/server/package.json index 874456b4d48a..e796975a42f3 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -61,6 +61,7 @@ "debug": "^4.3.4", "dirt-simple-file-cache": "^0.4.0", "duplexify": "4.1.2", + "edgedriver": "5.6.1", "electron-context-menu": "3.6.1", "errorhandler": "1.5.1", "evil-dns": "0.2.0", @@ -107,7 +108,6 @@ "pidusage": "3.0.2", "pluralize": "8.0.0", "pretty-bytes": "^5.6.0", - "pump": "^3.0.2", "randomstring": "1.3.0", "recast": "0.20.4", "resolve": "1.17.0", @@ -218,9 +218,9 @@ "nohoist": [ "@benmalka/foxdriver", "devtools-protocol", + "edgedriver", "geckodriver", "http-proxy", - "pump", "tsconfig-paths", "webdriver" ] diff --git a/packages/server/patches/edgedriver+5.6.1.patch b/packages/server/patches/edgedriver+5.6.1.patch new file mode 100644 index 000000000000..6aeef2b443d1 --- /dev/null +++ b/packages/server/patches/edgedriver+5.6.1.patch @@ -0,0 +1,237 @@ +diff --git a/node_modules/edgedriver/README.md b/node_modules/edgedriver/README.md +deleted file mode 100644 +index 3b361a7..0000000 +--- a/node_modules/edgedriver/README.md ++++ /dev/null +@@ -1,218 +0,0 @@ +-EdgeDriver [![CI](https://github.com/webdriverio-community/node-edgedriver/actions/workflows/ci.yml/badge.svg)](https://github.com/webdriverio-community/node-edgedriver/actions/workflows/ci.yml) [![Audit](https://github.com/webdriverio-community/node-edgedriver/actions/workflows/audit.yml/badge.svg)](https://github.com/webdriverio-community/node-edgedriver/actions/workflows/audit.yml) +-========== +- +-An NPM wrapper for Microsofts' [EdgeDriver](https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/). It manages to download various (or the latest) Edgedriver versions and provides a programmatic interface to start and stop it within Node.js. __Note:__ this is a wrapper module. If you discover any bugs with EdgeDriver, please report them in the [official repository](https://github.com/MicrosoftEdge/EdgeWebDriver). +- +-# Installing +- +-You can install this package via: +- +-```sh +-npm install edgedriver +-``` +- +-Once installed you can start Edgedriver via: +- +-```sh +-npx edgedriver --port=4444 +-``` +- +-By default, this package downloads Edgedriver when used for the first time through the CLI or the programmatical interface. If you like to download it as part of the NPM install process, set the `EDGEDRIVER_AUTO_INSTALL` environment flag, e.g.: +- +-```sh +-EDGEDRIVER_AUTO_INSTALL=1 npm i +-``` +- +-To get a list of available CLI options run `npx edgedriver --help`. By default this package tries to find the Mircosoft Edge version installed on a given system. If you prefer to have it install a custom EdgeDriver version you can define the environment variable `EDGEDRIVER_VERSION` when running in CLI, e.g.: +- +-```sh +-$ npm i edgedriver +-$ EDGEDRIVER_VERSION=105.0.1343.33 npx edgedriver --version +-Microsoft Edge WebDriver 105.0.1343.33 (4122bb4646b33f33bca5d269490b9caadfc452b2) +-``` +- +-# Programmatic Interface +- +-You can import this package with Node.js and start the driver as part of your script and use it e.g. with [WebdriverIO](https://webdriver.io). +- +-## Exported Methods +- +-The package exports a `start`, `findEdgePath` and `download` method. +- +-### `start` +- +-Starts an EdgeDriver instance and returns a [`ChildProcess`](https://nodejs.org/api/child_process.html#class-childprocess). If EdgeDriver is not downloaded it will download it for you. +- +-__Params:__ `EdgedriverParameters` - options to pass into EdgeDriver (see below) +- +-__Example:__ +- +-```js +-import { start } from 'edgedriver'; +-import { remote } from 'webdriverio'; +-import waitPort from 'wait-port'; +- +-/** +- * first start EdgeDriver +- */ +-const cp = await start({ port: 4444 }); +- +-/** +- * wait for EdgeDriver to be up +- */ +-await waitPort({ port: 4444 }); +- +-/** +- * then start WebdriverIO session +- */ +-const browser = await remote({ capabilities: { browserName: 'msedge' } }); +-await browser.url('https://webdriver.io'); +-console.log(await browser.getTitle()); // prints "WebdriverIO · Next-gen browser and mobile automation test framework for Node.js | WebdriverIO" +- +-/** +- * kill Edgedriver process +- */ +-cp.kill(); +-``` +- +-__Note:__ as you can see in the example above this package does not wait for the driver to be up, you have to manage this yourself through packages like [`wait-on`](https://github.com/jeffbski/wait-on). +- +-### `download` +- +-Method to download an EdgeDriver with a particular version. If version parameter is omitted it tries to detect the version based on the Edge browser installed on the system. +- +-__Params:__ `string` - version of Edgedriver to download (optional) +-__Returns:__ `string` - path to Edgedriver binary +- +-### `findEdgePath` +- +-The `findEdgePath` is a helper method to find the Microsoft Egde binary on given system. If there is a `EDGE_BINARY_PATH` environment set, it will return that value. +- +-__Returns:__ `string` - path to Microsoft Edge binary +- +-## CJS Support +- +-In case your module uses CJS you can use this package as follows: +- +-```js +-const { start } = require('edgedriver') +-// see example above +-``` +- +-## Custom CDN URL +- +-This allows you to use your own endpoints for downloading Edgedriver binaries. It is useful in air gapped scenarios or if you have download restrictions, such as firewalls. You can either set an environment variable: +- +-```sh +-$ npm i edgedriver +-$ EDGEDRIVER_CDNURL=https://msedgedriver.azureedge.net npx edgedriver --version +-``` +- +-or create a [`.npmrc`](https://docs.npmjs.com/cli/configuring-npm/npmrc) with the following content: +- +-```toml +-edgedriver_cdnurl=https://msedgedriver.azureedge.net +-``` +- +-## Options +- +-The `start` method offers the following options to be passed on to the actual Edgedriver CLI. +- +-### edgeDriverVersion +- +-The version of EdgeDriver to start. See [Egdedriver directory list](https://msedgewebdriverstorage.z22.web.core.windows.net/) for all available versions, platforms and architecture. +- +-Type: `number`
+-Default: `latest` +- +-### port +-The port on which the driver should run. +- +-Example: `9515`
+-Type: `number` +- +-### adbPort +-The port on which the ADB driver should run. +- +-Example: `9515`
+-Type: `number` +- +-### baseUrl +-Base URL path prefix for commands, e.g. `wd/url`. +- +-Example: `/` +- +-Type: `string` +- +-### logPath +-Write server log to file instead of stderr, increases log level to `INFO` +- +-Type: `string` +- +-### logLevel +-Set log level. Possible options `ALL`, `DEBUG`, `INFO`, `WARNING`, `SEVERE`, `OFF`. +- +-Type: `string` +- +-### verbose +-Log verbosely (equivalent to `--log-level=ALL`) +- +-Type: `boolean` +- +-### silent +-Log nothing (equivalent to `--log-level=OFF`) +- +-Type: `boolean` +- +-### appendLog +-Append log file instead of rewriting. +- +-Type: `boolean` +- +-### replayable +-Log verbosely and don't truncate long strings so that the log can be replayed (experimental). +- +-Type: `boolean` +- +-### readableTimestamp +-Add readable timestamps to log. +- +-Type: `boolean` +- +-### enableChromeLogs +-Show logs from the browser (overrides other logging options). +- +-Type: `boolean` +- +-### bidiMapperPath +-Custom bidi mapper path. +- +-Type: `string` +- +-### allowedIps +-Comma-separated allowlist of remote IP addresses which are allowed to connect to EdgeDriver. +- +-Type: `string[]`
+-Default: `['']` +- +-### allowedOrigins +-Comma-separated allowlist of request origins which are allowed to connect to EdgeDriver. Using `*` to allow any host origin is dangerous! +- +-Type: `string[]`
+-Default: `['*']` +- +-### cacheDir +-The path to the root of the cache directory. +- +-Type: `string`
+-Default: `process.env.EDGEDRIVER_CACHE_DIR || os.tmpdir()` +- +-### customEdgeDriverPath +-Don't download EdgeDriver, instead use a custom path to it, e.g. a cached binary. +- +-Type: `string`
+-Default: `process.env.EDGEDRIVER_PATH` +- +---- +- +-For more information on WebdriverIO see the [homepage](https://webdriver.io). +diff --git a/node_modules/edgedriver/dist/install.js b/node_modules/edgedriver/dist/install.js +index 99730a0..b71c6ad 100644 +--- a/node_modules/edgedriver/dist/install.js ++++ b/node_modules/edgedriver/dist/install.js +@@ -205,6 +205,6 @@ function sanitizeVersion(version) { + * download on install + */ + if (process.argv[1] && process.argv[1].endsWith('/dist/install.js') && Boolean(process.env.EDGEDRIVER_AUTO_INSTALL)) { +- await download().then(() => log.info('Success!'), (err) => log.error(`Failed to install Edgedriver: ${err.stack}`)); ++ download().then(() => log.info('Success!'), (err) => log.error(`Failed to install Edgedriver: ${err.stack}`)); + } + //# sourceMappingURL=install.js.map +\ No newline at end of file diff --git a/scripts/binary/binary-cleanup.js b/scripts/binary/binary-cleanup.js index da20a87c3f88..ec4729504193 100644 --- a/scripts/binary/binary-cleanup.js +++ b/scripts/binary/binary-cleanup.js @@ -50,6 +50,7 @@ const getDependencyPathsToKeep = async (buildAppDir) => { 'node_modules/html-webpack-plugin-4/index.js', 'node_modules/html-webpack-plugin-5/index.js', 'node_modules/mocha-7.0.1/index.js', + 'packages/server/node_modules/webdriver/build/index.js', ] let entryPoints = new Set([ diff --git a/yarn.lock b/yarn.lock index 6b174762f6a3..31402b3c8157 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14352,7 +14352,7 @@ edge-paths@^3.0.5: "@types/which" "^2.0.1" which "^2.0.2" -edgedriver@^5.6.1: +edgedriver@5.6.1, edgedriver@^5.6.1: version "5.6.1" resolved "https://registry.npmjs.org/edgedriver/-/edgedriver-5.6.1.tgz#36971f000aee8756c11f3fb1dc5273f109e860d5" integrity sha512-3Ve9cd5ziLByUdigw6zovVeWJjVs8QHVmqOB0sJ0WNeVPcwf4p18GnxMmVvlFmYRloUwf5suNuorea4QzwBIOA== @@ -25860,7 +25860,7 @@ pump@^2.0.0: end-of-stream "^1.1.0" once "^1.3.1" -pump@^3.0.0, pump@^3.0.2: +pump@^3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz#836f3edd6bc2ee599256c924ffe0d88573ddcbf8" integrity sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw== From 226c5ae673e921b0449747ea716ea12050d3d548 Mon Sep 17 00:00:00 2001 From: Bill Glesias Date: Wed, 9 Oct 2024 12:01:51 -0400 Subject: [PATCH 15/22] fix issues with firefox profile not being created in open mode when old profile exists from previous cypress versions where they are no longer compatible [run ci] --- packages/server/lib/browsers/firefox.ts | 95 ++++++++++++------- .../server/test/unit/browsers/firefox_spec.ts | 52 ++++++---- 2 files changed, 93 insertions(+), 54 deletions(-) diff --git a/packages/server/lib/browsers/firefox.ts b/packages/server/lib/browsers/firefox.ts index 5a4e55506b05..5cac9857b4ba 100644 --- a/packages/server/lib/browsers/firefox.ts +++ b/packages/server/lib/browsers/firefox.ts @@ -457,6 +457,21 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc // this is so the BiDi websocket port does not get set to 0, which is the default for the geckodriver package. debug('available ports: %o', { foxdriverPort, marionettePort, webDriverBiDiPort }) + const profileDir = utils.getProfileDir(browser, options.isTextTerminal) + + // Delete the profile directory if in open mode. + // Cypress does this because profiles are sourced and created differently with geckodriver/webdriver. + // the profile creation method before 13.15.0 will no longer work with geckodriver/webdriver + // and actually corrupts the profile directory from being able to be encoded. Hence, we delete it to prevent any conflicts. + // This is critical to make sure different Cypress versions do not corrupt the firefox profile, which can fail silently. + if (!options.isTextTerminal) { + const doesPathExist = await fs.pathExists(profileDir) + + if (doesPathExist) { + await fs.remove(profileDir) + } + } + const [ cacheDir, extensionDest, @@ -474,12 +489,13 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc launchOptions.extensions = [extensionDest] } - const profileDir = utils.getProfileDir(browser, options.isTextTerminal) - const profile = new FirefoxProfile({ destinationDirectory: profileDir, }) + // make sure the profile that is ported into the session is destroyed when the browser is closed + profile.shouldDeleteOnExit(true) + debug('firefox directories %o', { path: profile.path(), cacheDir, extensionDest }) const xulStorePath = path.join(profile.path(), 'xulstore.json') @@ -488,7 +504,15 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc if (!await fs.pathExists(xulStorePath)) { // this causes the browser to launch maximized, which chrome does by default // otherwise an arbitrary size will be picked for the window size - // this will not have an effect after first launch in 'interactive' mode + + // this used to not have an effect after first launch in 'interactive' mode. + // However, since Cypress 13.15.1, + // geckodriver creates unique profile names that copy over the xulstore.json to the used profile. + // The copy is ultimately updated on the unique profile name and is destroyed when the browser is torn down, + // so the values are not persisted. Cypress could hypothetically determine the profile in use, copy the xulstore.json + // out of the profile and try to persist it in the next created profile, but this method is likely error prone as it requires + // moving/copying of files while creation/deletion of profiles occur, plus the ability to coorelate the correct profile to the current run, + // which there are not guarantees we can deterministically do this in open mode. const sizemode = 'maximized' await fs.writeJSON(xulStorePath, { 'chrome://browser/content/browser.xhtml': { 'main-window': { 'width': 1280, 'height': 1024, sizemode } } }) @@ -557,7 +581,13 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc logNoTruncate: Debug.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE), } - /** + // @ts-expect-error + let browserInstanceWrapper: BrowserInstance = new EventEmitter() + + browserInstanceWrapper.kill = () => undefined + + try { + /** * To set the profile, we use the profile capabilities in firefoxOptions which * requires the profile to be base64 encoded. The profile will be copied over to whatever * profile is created by geckodriver stemming from the root profile path. @@ -567,42 +597,37 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc * copy it to a profile created in the profile root, which would look something like /usr/foo/firefox-stable/run-12345/rust_mozprofile/* * @see https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions */ - const base64EncodedProfile = await new Promise((resolve, reject) => { - profile.encoded(function (err, encodedProfile) { - err ? reject(err) : resolve(encodedProfile) + const base64EncodedProfile = await new Promise((resolve, reject) => { + profile.encoded(function (err, encodedProfile) { + err ? reject(err) : resolve(encodedProfile) + }) }) - }) - const newSessionCapabilities: RemoteConfig = { - logLevel: Debug.enabled(WEBDRIVER_DEBUG_NAMESPACE_VERBOSE) ? 'info' : 'silent', - capabilities: { - alwaysMatch: { - browserName: 'firefox', - acceptInsecureCerts: true, - // @see https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions - 'moz:firefoxOptions': { - profile: base64EncodedProfile, - binary: browser.path, - args: launchOptions.args, - prefs: launchOptions.preferences, + const newSessionCapabilities: RemoteConfig = { + logLevel: Debug.enabled(WEBDRIVER_DEBUG_NAMESPACE_VERBOSE) ? 'info' : 'silent', + capabilities: { + alwaysMatch: { + browserName: 'firefox', + acceptInsecureCerts: true, + // @see https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions + 'moz:firefoxOptions': { + profile: base64EncodedProfile, + binary: browser.path, + args: launchOptions.args, + prefs: launchOptions.preferences, + }, + // @see https://firefox-source-docs.mozilla.org/testing/geckodriver/Capabilities.html#moz-debuggeraddress + // we specify the debugger address option for Webdriver, which will return us the CDP address when the capability is returned. + // @ts-expect-error + 'moz:debuggerAddress': true, + // @see https://webdriver.io/docs/capabilities/#wdiogeckodriveroptions + // webdriver starts geckodriver with the correct options on behalf of Cypress + 'wdio:geckodriverOptions': geckoDriverOptions, }, - // @see https://firefox-source-docs.mozilla.org/testing/geckodriver/Capabilities.html#moz-debuggeraddress - // we specify the debugger address option for Webdriver, which will return us the CDP address when the capability is returned. - // @ts-expect-error - 'moz:debuggerAddress': true, - // @see https://webdriver.io/docs/capabilities/#wdiogeckodriveroptions - // webdriver starts geckodriver with the correct options on behalf of Cypress - 'wdio:geckodriverOptions': geckoDriverOptions, + firstMatch: [], }, - firstMatch: [], - }, - } - // @ts-expect-error - let browserInstanceWrapper: BrowserInstance = new EventEmitter() - - browserInstanceWrapper.kill = () => undefined + } - try { debugVerbose(`creating session with capabilities %s`, JSON.stringify(newSessionCapabilities.capabilities)) const WD = WebDriver.getWebDriverPackage() diff --git a/packages/server/test/unit/browsers/firefox_spec.ts b/packages/server/test/unit/browsers/firefox_spec.ts index 2195ebd850e6..0b0a13c65da1 100644 --- a/packages/server/test/unit/browsers/firefox_spec.ts +++ b/packages/server/test/unit/browsers/firefox_spec.ts @@ -4,6 +4,7 @@ import { expect } from 'chai' import debug from 'debug' import os from 'os' import sinon from 'sinon' +import fsExtra from 'fs-extra' import Foxdriver from '@benmalka/foxdriver' import * as firefox from '../../../lib/browsers/firefox' import firefoxUtil from '../../../lib/browsers/firefox-util' @@ -82,10 +83,10 @@ describe('lib/browsers/firefox', () => { }, } - wdInstance.maximizeWindow.resolves(null), - wdInstance.installAddOn.resolves(null), - wdInstance.switchToWindow.resolves(null), - wdInstance.navigateTo.resolves(null), + wdInstance.maximizeWindow.resolves(undefined) + wdInstance.installAddOn.resolves(undefined) + wdInstance.switchToWindow.resolves(undefined) + wdInstance.navigateTo.resolves(undefined) sinon.stub(webdriver, 'newSession').resolves(wdInstance) @@ -116,9 +117,14 @@ describe('lib/browsers/firefox', () => { sinon.stub(utils, 'writeExtension').resolves('/path/to/ext') sinon.stub(utils, 'getPort').resolves(1234) sinon.spy(FirefoxProfile.prototype, 'setPreference') - sinon.spy(FirefoxProfile.prototype, 'updatePreferences') + sinon.spy(FirefoxProfile.prototype, 'shouldDeleteOnExit') sinon.spy(FirefoxProfile.prototype, 'path') + sinon.stub(FirefoxProfile.prototype, 'encoded').callsFake((cb) => { + cb(undefined, 'abcdef') + }) + sinon.stub(fsExtra, 'writeJSON').resolves(undefined) + sinon.stub(fsExtra, 'writeFile').resolves(undefined) browserCriClient = sinon.createStubInstance(BrowserCriClient) browserCriClient.attachToTargetUrl = sinon.stub().resolves({}) @@ -458,6 +464,12 @@ describe('lib/browsers/firefox', () => { expect(FirefoxProfile.prototype.setPreference).not.to.be.calledWith('network.proxy.no_proxies_on') }) + it('tears down the temporary profile when the browser is destroyed', async function () { + await firefox.open(this.browser, 'http://', this.options, this.automation) + + expect(FirefoxProfile.prototype.shouldDeleteOnExit).to.be.calledWith(true) + }) + // @see https://github.com/cypress-io/cypress/issues/17896 it('escapes the downloadsFolders path correctly when running on Windows OS', async function () { this.options.proxyServer = 'http://proxy-server:1234' @@ -498,7 +510,7 @@ describe('lib/browsers/firefox', () => { expect(result.kill).to.be.an.instanceof(Function) }) - it('does not clear user profile if already exists', async function () { + it('always clear user profile if it already exists', async function () { mockfs({ '/path/to/appData/firefox-stable/interactive/': { 'xulstore.json': '[foo xulstore.json]', @@ -508,24 +520,29 @@ describe('lib/browsers/firefox', () => { await firefox.open(this.browser, 'http://', this.options, this.automation) - // @ts-ignore - expect(specUtil.getFsPath('/path/to/appData/firefox-stable/interactive')).containSubset({ - 'xulstore.json': '[foo xulstore.json]', - 'chrome': { 'userChrome.css': '[foo userChrome.css]' }, - }) + expect(specUtil.getFsPath('/path/to/appData/firefox-stable/interactive')).to.be.undefined }) it('creates xulstore.json if not exist', async function () { await firefox.open(this.browser, 'http://', this.options, this.automation) - // @ts-ignore - expect(specUtil.getFsPath('/path/to/appData/firefox-stable/interactive')).containSubset({ - 'xulstore.json': '{"chrome://browser/content/browser.xhtml":{"main-window":{"width":1280,"height":1024,"sizemode":"maximized"}}}\n', + expect(fsExtra.writeJSON).to.have.been.calledWith('/path/to/appData/firefox-stable/interactive/xulstore.json', { + 'chrome://browser/content/browser.xhtml': + { + 'main-window': + { + 'width': 1280, + 'height': 1024, + 'sizemode': 'maximized', + }, + }, + }) }) it('creates chrome/userChrome.css if not exist', async function () { await firefox.open(this.browser, 'http://', this.options, this.automation) - expect(specUtil.getFsPath('/path/to/appData/firefox-stable/interactive/chrome/userChrome.css')).ok + + expect(fsExtra.writeFile).to.have.been.calledWith('/path/to/appData/firefox-stable/interactive/chrome/userChrome.css') }) it('clears browser cache', async function () { @@ -538,10 +555,7 @@ describe('lib/browsers/firefox', () => { this.options.isTextTerminal = false await firefox.open(this.browser, 'http://', this.options, this.automation) - // @ts-ignore - expect(specUtil.getFsPath('/path/to/appData/firefox-stable/interactive')).containSubset({ - 'CypressCache': {}, - }) + expect(specUtil.getFsPath('/path/to/appData/firefox-stable/interactive')).to.be.undefined }) it('wraps errors when retrying socket fails', async function () { From e204aab3f69c16ca7ea87a11a51bac39ca6b2d39 Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Wed, 9 Oct 2024 17:01:42 -0400 Subject: [PATCH 16/22] address comments that came up in review [run ci] --- packages/server/lib/browsers/firefox.ts | 12 ++++++---- .../server/lib/browsers/webdriver/index.ts | 23 ------------------- .../server/patches/edgedriver+5.6.1.patch | 7 ++++-- system-tests/lib/pluginUtils.js | 3 +-- 4 files changed, 14 insertions(+), 31 deletions(-) diff --git a/packages/server/lib/browsers/firefox.ts b/packages/server/lib/browsers/firefox.ts index 5cac9857b4ba..4e3ce8693e22 100644 --- a/packages/server/lib/browsers/firefox.ts +++ b/packages/server/lib/browsers/firefox.ts @@ -20,11 +20,15 @@ import { getCtx } from '@packages/data-context' import { getError } from '@packages/errors' import type { BrowserLaunchOpts, BrowserNewTabOpts, RunModeVideoApi } from '@packages/types' import type { RemoteConfig } from 'webdriver' -import { GeckoDriverOptions, WebDriver } from './webdriver' +import type { GeckodriverParameters } from 'geckodriver' +import { WebDriver } from './webdriver' const debug = Debug('cypress:server:browsers:firefox') const debugVerbose = Debug('cypress-verbose:server:browsers:firefox') +// These debug variables have an impact on the 3rd-party webdriver and geckodriver +// packages. To see verbose logs from Firefox, set both of these options to the +// DEBUG variable. const WEBDRIVER_DEBUG_NAMESPACE_VERBOSE = 'cypress-verbose:server:browsers:webdriver' const GECKODRIVER_DEBUG_NAMESPACE_VERBOSE = 'cypress-verbose:server:browsers:geckodriver' @@ -544,8 +548,7 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc } // resolution of exactly 1280x720 - // (height must account for firefox url bar, which we can only shrink to 1px , - // and the total size of the window url and tab bar, which is 85 pixels for a total offset of 86 pixels) + // (height must account for firefox url bar, which we can only shrink to 2px) const BROWSER_ENVS = { MOZ_REMOTE_SETTINGS_DEVTOOLS: '1', MOZ_HEADLESS_WIDTH: '1280', @@ -557,7 +560,7 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc debug('launch in firefox', { url, args: launchOptions.args }) - const geckoDriverOptions: GeckoDriverOptions = { + const geckoDriverOptions: GeckodriverParameters = { host: '127.0.0.1', // geckodriver port is assigned under the hood by @wdio/utils // @see https://github.com/webdriverio/webdriverio/blob/v9.1.1/packages/wdio-utils/src/node/startWebDriver.ts#L65 @@ -578,6 +581,7 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc }, jsdebugger: Debug.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE) || false, log: Debug.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE) ? 'debug' : 'error', + // @ts-expect-error logNoTruncate: Debug.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE), } diff --git a/packages/server/lib/browsers/webdriver/index.ts b/packages/server/lib/browsers/webdriver/index.ts index 19648325c7cf..e586119b9f75 100644 --- a/packages/server/lib/browsers/webdriver/index.ts +++ b/packages/server/lib/browsers/webdriver/index.ts @@ -1,30 +1,7 @@ -import type { SpawnOptionsWithoutStdio, SpawnOptionsWithStdioTuple, StdioNull, StdioPipe } from 'child_process' import type WebDriverPackage from 'webdriver' const webDriverPackageName = 'webdriver' -type StdioOption = StdioNull | StdioPipe - -export type GeckoDriverOptions = { - allowHosts?: string[] - allowOrigins?: string[] - binary?: string - connectExisting?: boolean - host?: string - jsdebugger?: boolean - log?: 'fatal' | 'error' | 'warn' | 'info' | 'config' | 'debug' | 'trace' - logNoTruncate?: boolean - marionetteHost?: string - marionettePort?: number - port?: number - websocketPort?: number - profileRoot?: string - geckoDriverVersion?: string - customGeckoDriverPath?: string - cacheDir?: string - spawnOpts: SpawnOptionsWithoutStdio | SpawnOptionsWithStdioTuple -} - export class WebDriver { // We resolve this package in such a way to packherd can discover it. static getWebDriverPackage: () => typeof WebDriverPackage = () => { diff --git a/packages/server/patches/edgedriver+5.6.1.patch b/packages/server/patches/edgedriver+5.6.1.patch index 6aeef2b443d1..ec35c3a94c95 100644 --- a/packages/server/patches/edgedriver+5.6.1.patch +++ b/packages/server/patches/edgedriver+5.6.1.patch @@ -223,14 +223,17 @@ index 3b361a7..0000000 - -For more information on WebdriverIO see the [homepage](https://webdriver.io). diff --git a/node_modules/edgedriver/dist/install.js b/node_modules/edgedriver/dist/install.js -index 99730a0..b71c6ad 100644 +index 99730a0..30e63c0 100644 --- a/node_modules/edgedriver/dist/install.js +++ b/node_modules/edgedriver/dist/install.js -@@ -205,6 +205,6 @@ function sanitizeVersion(version) { +@@ -205,6 +205,9 @@ function sanitizeVersion(version) { * download on install */ if (process.argv[1] && process.argv[1].endsWith('/dist/install.js') && Boolean(process.env.EDGEDRIVER_AUTO_INSTALL)) { - await download().then(() => log.info('Success!'), (err) => log.error(`Failed to install Edgedriver: ${err.stack}`)); ++ // removing the await here as packherd cannot bundle with a top-level await. ++ // This only has an impact if invoking from a CLI context, which cypress is not. ++ // Cypress actually does not directly use this package in any way. + download().then(() => log.info('Success!'), (err) => log.error(`Failed to install Edgedriver: ${err.stack}`)); } //# sourceMappingURL=install.js.map diff --git a/system-tests/lib/pluginUtils.js b/system-tests/lib/pluginUtils.js index 618b0139acdf..0ffdd3f6a5da 100644 --- a/system-tests/lib/pluginUtils.js +++ b/system-tests/lib/pluginUtils.js @@ -5,8 +5,7 @@ module.exports = { if (browser.family === 'firefox') { // this is needed to ensure correct error screenshot / video recording // resolution of exactly 1280x720 - // (height must account for firefox url bar, which we can only shrink to 1px , - // and the total size of the window url and tab bar, which is 85 pixels for a total offset of 86 pixels) + // (height must account for firefox url bar, which we can only shrink to 2px) options.args.push( '-width', '1280', '-height', '722', ) From a2b40a6924956b4a3c98db45d0b4669e9498342e Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Wed, 9 Oct 2024 22:26:12 -0400 Subject: [PATCH 17/22] see if this fixes extension test [run ci] --- .../server/test/unit/browsers/firefox_spec.ts | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/packages/server/test/unit/browsers/firefox_spec.ts b/packages/server/test/unit/browsers/firefox_spec.ts index 0b0a13c65da1..b4239c123069 100644 --- a/packages/server/test/unit/browsers/firefox_spec.ts +++ b/packages/server/test/unit/browsers/firefox_spec.ts @@ -15,7 +15,6 @@ import { type Client as WebDriverClient, default as webdriver } from 'webdriver' import { EventEmitter } from 'stream' const path = require('path') -const _ = require('lodash') const mockfs = require('mock-fs') const FirefoxProfile = require('firefox-profile') const utils = require('../../../lib/browsers/utils') @@ -119,12 +118,12 @@ describe('lib/browsers/firefox', () => { sinon.spy(FirefoxProfile.prototype, 'setPreference') sinon.spy(FirefoxProfile.prototype, 'shouldDeleteOnExit') sinon.spy(FirefoxProfile.prototype, 'path') - sinon.stub(FirefoxProfile.prototype, 'encoded').callsFake((cb) => { + sinon.stub(FirefoxProfile.prototype, 'encoded').callsFake((cb: Function) => { cb(undefined, 'abcdef') }) sinon.stub(fsExtra, 'writeJSON').resolves(undefined) - sinon.stub(fsExtra, 'writeFile').resolves(undefined) + sinon.stub(fsExtra, 'writeFile').returns(undefined) browserCriClient = sinon.createStubInstance(BrowserCriClient) browserCriClient.attachToTargetUrl = sinon.stub().resolves({}) @@ -393,11 +392,6 @@ describe('lib/browsers/firefox', () => { }) it('writes extension and ensure write access', async function () { - // TODO: Test is failing locally, figure out why?? - if (!process.env.CI) { - return - } - mockfs({ [path.resolve(`${__dirname }../../../../../extension/dist/v2`)]: { 'background.js': mockfs.file({ @@ -418,16 +412,16 @@ describe('lib/browsers/firefox', () => { }) utils.writeExtension.restore() + // @ts-expect-error + fsExtra.writeFile.restore() + sinon.spy(fsExtra, 'chmod') - const getFile = function (path) { - return _.reduce(_.compact(_.split(path, '/')), (acc, item) => { - return acc.getItem(item) - }, mockfs.getMockRoot()) - } + // bypass the extension clearing that happens in open mode, which is tested at the system test level + this.options.isTextTerminal = true await firefox.open(this.browser, 'http://', this.options, this.automation) - expect(getFile(`${process.env.HOME }/.config/Cypress/cy/test/browsers/firefox-stable/interactive/CypressExtension/background.js`).getMode()).to.be.equals(0o644) + expect(fsExtra.chmod).to.have.been.calledWith(sinon.match(/CypressExtension\/background\.js/), 0o644) }) it('sets proxy-related preferences if specified', async function () { From 132ab0772aae1cfbb296a559d253ce2d390554de Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Thu, 10 Oct 2024 11:03:59 -0400 Subject: [PATCH 18/22] make sure process kill emits the exit event [run ci] --- packages/server/lib/browsers/firefox.ts | 4 ++++ packages/server/test/unit/browsers/firefox_spec.ts | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/server/lib/browsers/firefox.ts b/packages/server/lib/browsers/firefox.ts index 4e3ce8693e22..2a38c42684ba 100644 --- a/packages/server/lib/browsers/firefox.ts +++ b/packages/server/lib/browsers/firefox.ts @@ -668,6 +668,10 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc debug('closing geckodriver and webdriver') const driverReturnStatus = process.kill(driverPID) + // needed for closing the browser when switching browsers in open mode to signal + // the browser is done closing + browserInstanceWrapper.emit('exit') + return browserReturnStatus || driverReturnStatus } diff --git a/packages/server/test/unit/browsers/firefox_spec.ts b/packages/server/test/unit/browsers/firefox_spec.ts index b4239c123069..f492d6269671 100644 --- a/packages/server/test/unit/browsers/firefox_spec.ts +++ b/packages/server/test/unit/browsers/firefox_spec.ts @@ -589,9 +589,11 @@ describe('lib/browsers/firefox', () => { expect(instance).to.be.an.instanceof(EventEmitter) }) - it('kills the driver and browser PIDs when the kill method is called', async function () { + it('kills the driver and browser PIDs when the kill method is called and emits the exit event', async function () { sinon.stub(process, 'kill').returns(true) const instance = await firefox.open(this.browser, 'http://', this.options, this.automation) + + sinon.spy(instance, 'emit') const killResult = instance.kill() expect(killResult).to.be.true @@ -600,6 +602,8 @@ describe('lib/browsers/firefox', () => { // kills the webdriver process/ geckodriver process expect(process.kill).to.have.been.calledWith(5678) expect(browserCriClient.close).to.have.been.called + // makes sure the exit event is called to signal to the rest of cypress server that the processes are killed + expect(instance.emit).to.have.been.calledWith('exit') }) }) }) From 5d1aa64715051fb6a38500bdc9de02708fe343ad Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Thu, 10 Oct 2024 11:37:18 -0400 Subject: [PATCH 19/22] update geckodriver to include contribution patch to types [run ci] --- packages/server/lib/browsers/firefox.ts | 3 +- packages/server/package.json | 2 +- .../server/patches/geckodriver+4.5.0.patch | 278 ------------------ yarn.lock | 8 +- 4 files changed, 7 insertions(+), 284 deletions(-) delete mode 100644 packages/server/patches/geckodriver+4.5.0.patch diff --git a/packages/server/lib/browsers/firefox.ts b/packages/server/lib/browsers/firefox.ts index 2a38c42684ba..122e46d7d4bf 100644 --- a/packages/server/lib/browsers/firefox.ts +++ b/packages/server/lib/browsers/firefox.ts @@ -581,10 +581,11 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc }, jsdebugger: Debug.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE) || false, log: Debug.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE) ? 'debug' : 'error', - // @ts-expect-error logNoTruncate: Debug.enabled(GECKODRIVER_DEBUG_NAMESPACE_VERBOSE), } + // since we no longer directly control the browser with webdriver, we need to make the browserInstance + // a simulated wrapper that kills the process IDs that come back from webdriver // @ts-expect-error let browserInstanceWrapper: BrowserInstance = new EventEmitter() diff --git a/packages/server/package.json b/packages/server/package.json index e796975a42f3..ba5cf7f3ffeb 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -72,7 +72,7 @@ "firefox-profile": "4.7.0", "fluent-ffmpeg": "2.1.2", "fs-extra": "9.1.0", - "geckodriver": "4.5.0", + "geckodriver": "4.5.1", "get-port": "5.1.1", "getos": "3.2.1", "glob": "7.1.3", diff --git a/packages/server/patches/geckodriver+4.5.0.patch b/packages/server/patches/geckodriver+4.5.0.patch deleted file mode 100644 index 77ea1dcef764..000000000000 --- a/packages/server/patches/geckodriver+4.5.0.patch +++ /dev/null @@ -1,278 +0,0 @@ -diff --git a/node_modules/geckodriver/README.md b/node_modules/geckodriver/README.md -deleted file mode 100644 -index 95e3ef0..0000000 ---- a/node_modules/geckodriver/README.md -+++ /dev/null -@@ -1,239 +0,0 @@ --Geckodriver [![CI](https://github.com/webdriverio-community/node-geckodriver/actions/workflows/ci.yml/badge.svg)](https://github.com/webdriverio-community/node-geckodriver/actions/workflows/ci.yml) [![Audit](https://github.com/webdriverio-community/node-geckodriver/actions/workflows/audit.yml/badge.svg)](https://github.com/webdriverio-community/node-geckodriver/actions/workflows/audit.yml) --========== -- --An NPM wrapper for Mozilla's [Geckodriver](https://github.com/mozilla/geckodriver). It manages to download various (or the latest) Geckodriver versions and provides a programmatic interface to start and stop it within Node.js. __Note:__ this is a wrapper module. If you discover any bugs with Geckodriver, please report them in the [official repository](https://github.com/mozilla/geckodriver). -- --# Installing -- --You can install this package via: -- --```sh --npm install geckodriver --``` -- --Or install it globally: -- --```sh --npm install -g geckodriver --``` -- --__Note:__ This installs a `geckodriver` shell script that runs the executable, but on Windows, [`selenium-webdriver`](https://www.npmjs.com/package/selenium-webdriver) looks for `geckodriver.exe`. To use a global installation of this package with [`selenium-webdriver`](https://www.npmjs.com/package/selenium-webdriver) on Windows, copy or link `geckodriver.exe` to a location on your `PATH` (such as the NPM bin directory) after installing this package: -- --```sh --mklink %USERPROFILE%\AppData\Roaming\npm\geckodriver.exe %USERPROFILE%\AppData\Roaming\npm\node_modules\geckodriver\geckodriver.exe --``` -- --Once installed you can start Geckodriver via: -- --```sh --npx geckodriver --port=4444 --``` -- --By default, this package downloads Geckodriver when used for the first time through the CLI or the programmatic interface. If you like to download it as part of the NPM install process, set the `GECKODRIVER_AUTO_INSTALL` environment flag, e.g.: -- --```sh --GECKODRIVER_AUTO_INSTALL=1 npm i --``` -- --To get a list of available CLI options run `npx geckodriver --help`. By default, this package downloads the latest version of the driver. If you prefer to have it install a custom Geckodriver version you can define the environment variable `GECKODRIVER_VERSION` when running in CLI, e.g.: -- --```sh --$ npm i geckodriver --$ GECKODRIVER_VERSION="0.31.0" npx geckodriver --version --geckodriver 0.31.0 (b617178ef491 2022-04-06 11:57 +0000) -- --The source code of this program is available from --testing/geckodriver in https://hg.mozilla.org/mozilla-central. -- --This program is subject to the terms of the Mozilla Public License 2.0. --You can obtain a copy of the license at https://mozilla.org/MPL/2.0/. --``` -- --## Setting a CDN URL for binary download -- --To set an alternate CDN location for Geckodriver binaries, set the `GECKODRIVER_CDNURL` like this: -- --```sh --GECKODRIVER_CDNURL=https://INTERNAL_CDN/geckodriver/download --``` -- --Binaries on your CDN should be located in a subdirectory of the above base URL. For example, `/vxx.xx.xx/*.tar.gz` should be located under `/geckodriver/download` above. -- --Alternatively, you can add the same property to your .npmrc file. -- --The default location is set to https://github.com/mozilla/geckodriver/releases/download -- --## Setting a PROXY URL -- --Use `HTTPS_PROXY` or `HTTP_PROXY` to set your proxy URL. -- --# Programmatic Interface -- --You can import this package with Node.js and start the driver as part of your script and use it e.g. with [WebdriverIO](https://webdriver.io). -- --## Exported Methods -- --The package exports a `start` and `download` method. -- --### `start` -- --Starts a Geckodriver instance and returns a [`ChildProcess`](https://nodejs.org/api/child_process.html#class-childprocess). If Geckodriver is not downloaded it will download it for you. -- --__Params:__ `GeckodriverParameters` - options to pass into Geckodriver (see below) -- --__Example:__ -- --```js --import { start } from 'geckodriver'; --import { remote } from 'webdriverio'; --import waitPort from 'wait-port'; -- --/** -- * first start Geckodriver -- */ --const cp = await start({ port: 4444 }); -- --/** -- * wait for Geckodriver to be up -- */ --await waitPort({ port: 4444 }); -- --/** -- * then start WebdriverIO session -- */ --const browser = await remote({ capabilities: { browserName: 'firefox' } }); --await browser.url('https://webdriver.io'); --console.log(await browser.getTitle()); // prints "WebdriverIO · Next-gen browser and mobile automation test framework for Node.js | WebdriverIO" -- --/** -- * kill Geckodriver process -- */ --cp.kill(); --``` -- --__Note:__ as you can see in the example above this package does not wait for the driver to be up, you have to manage this yourself through packages like [`wait-on`](https://github.com/jeffbski/wait-on). -- --### `download` -- --Method to download a Geckodriver with a particular version. If a version parameter is omitted it tries to download the latest available version of the driver. -- --__Params:__ `string` - version of Geckodriver to download (optional) -- --## CJS Support -- --In case your module uses CJS you can use this package as follows: -- --```js --const { start } = require('geckodriver') --// see example above --``` -- --## Options -- --The `start` method offers the following options to be passed on to the actual Geckodriver CLI. -- --### `allowHosts` -- --List of host names to allow. By default, the value of --host is allowed, and in addition, if that's a well-known local address, other variations on well-known local addresses are allowed. If --allow-hosts is provided only exactly those hosts are allowed. -- --Type: `string[]`
--Default: `[]` -- --### `allowOrigins` --List of request origins to allow. These must be formatted as `scheme://host:port`. By default, any request with an origin header is rejected. If `--allow-origins` is provided then only exactly those origins are allowed. -- --Type: `string[]`
--Default: `[]` -- --### `binary` --Path to the Firefox binary. -- --Type: `string` -- --### `connectExisting` --Connect to an existing Firefox instance. -- --Type: `boolean`
--Default: `false` -- --### `host` --Host IP to use for WebDriver server. -- --Type: `string`
--Default: `0.0.0.0` -- --### `jsdebugger` --Attach browser toolbox debugger for Firefox. -- --Type: `boolean`
--Default: `false` -- --### `log` --Set Gecko log level [possible values: `fatal`, `error`, `warn`, `info`, `config`, `debug`, `trace`]. -- --Type: `string` -- --### `logNoTruncated` --Write server log to file instead of stderr, increases log level to `INFO`. -- --Type: `boolean` -- --### `marionetteHost` --Host to use to connect to Gecko. -- --Type: `boolean`
--Default: `127.0.0.1` -- --### `marionettePort` --Port to use to connect to Gecko. -- --Type: `number`
--Default: `0` -- --### `port` --Port to listen on. -- --Type: `number` -- --### `profileRoot` --Directory in which to create profiles. Defaults to the system temporary directory. -- --Type: `string` -- --### `geckoDriverVersion` --A version of Geckodriver to start. See https://github.com/mozilla/geckodriver/releases for all available versions, platforms and architecture. -- --Type: `string` -- --### `customGeckoDriverPath` --Don't download Geckodriver, instead use a custom path to it, e.g. a cached binary. -- --Type: `string`
--Default: `process.env.GECKODRIVER_PATH` -- --### `cacheDir` --The path to the root of the cache directory. -- --Type: `string`
--Default: `process.env.GECKODRIVER_CACHE_DIR || os.tmpdir()` -- --### `spawnOpts` --Options to pass into the geckodriver process. This can be useful if needing --Firefox to spawn with `MOZ_` prefix variables, such as `MOZ_HEADLESS_WIDTH`. --See https://nodejs.org/api/child_process.html#child_processspawncommand-args-options for --all options. -- --Type: `SpawnOptionsWithoutStdio | SpawnOptionsWithStdioTuple`
--Default: `undefined` -- --# Other Browser Driver -- --If you also look for other browser driver NPM wrappers, you can find them here: -- --- Chrome: [giggio/node-chromedriver](https://github.com/giggio/node-chromedriver) --- Microsoft Edge: [webdriverio-community/node-edgedriver](https://github.com/webdriverio-community/node-edgedriver) --- Safari: [webdriverio-community/node-safaridriver](https://github.com/webdriverio-community/node-safaridriver) -- ----- -- --For more information on WebdriverIO see the [homepage](https://webdriver.io). -diff --git a/node_modules/geckodriver/dist/index.js b/node_modules/geckodriver/dist/index.js -index 2edc6d2..8d6132d 100644 ---- a/node_modules/geckodriver/dist/index.js -+++ b/node_modules/geckodriver/dist/index.js -@@ -1,10 +1,13 @@ - import cp from 'node:child_process'; - import logger from '@wdio/logger'; -+import debugModule from 'debug' - import { download as downloadDriver } from './install.js'; - import { hasAccess, parseParams } from './utils.js'; - import { DEFAULT_HOSTNAME } from './constants.js'; - const log = logger('geckodriver'); - export async function start(params) { -+ // wrap in cypress debugger statement to avoid extraneous messages to the console -+ log.setLevel(debugModule.enabled('cypress-verbose:server:browsers:geckodriver') ? 'info' : 'silent') - const { cacheDir, customGeckoDriverPath, spawnOpts, ...startArgs } = params; - let geckoDriverPath = (customGeckoDriverPath || - process.env.GECKODRIVER_PATH || -diff --git a/node_modules/geckodriver/dist/install.js b/node_modules/geckodriver/dist/install.js -index c27c805..ac53518 100644 ---- a/node_modules/geckodriver/dist/install.js -+++ b/node_modules/geckodriver/dist/install.js -@@ -70,6 +70,8 @@ async function downloadZip(res, cacheDir) { - * download on install - */ - if (process.argv[1] && process.argv[1].endsWith('/dist/install.js') && process.env.GECKODRIVER_AUTO_INSTALL) { -- await download().then(() => log.info('Success!'), (err) => log.error(`Failed to install Geckodriver: ${err.stack}`)); -+ // removing the await here as packherd cannot bundle with a top-level await. -+ // This only has an impact if invoking from a CLI context, which cypress is not. -+ download().then(() => log.info('Success!'), (err) => log.error(`Failed to install Geckodriver: ${err.stack}`)); - } - //# sourceMappingURL=install.js.map -\ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 31402b3c8157..0461818d61c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16941,10 +16941,10 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -geckodriver@4.5.0, geckodriver@^4.3.3: - version "4.5.0" - resolved "https://registry.npmjs.org/geckodriver/-/geckodriver-4.5.0.tgz#a2a4e526ac657af7d21089727218adddd750080f" - integrity sha512-EnBCT9kJ5oEoP3DaJKjzxAhm7bbNNK6k2q7oCkCT58OIOOiE6Hsr+nVDHflsNaR68HMGtBKOLSZ+YvCDHecScw== +geckodriver@4.5.1, geckodriver@^4.3.3: + version "4.5.1" + resolved "https://registry.npmjs.org/geckodriver/-/geckodriver-4.5.1.tgz#624fc01815c1aa498dd3f717f7bd4c6cca0c57b8" + integrity sha512-lGCRqPMuzbRNDWJOQcUqhNqPvNsIFu6yzXF8J/6K3WCYFd2r5ckbeF7h1cxsnjA7YLSEiWzERCt6/gjZ3tW0ug== dependencies: "@wdio/logger" "^9.0.0" "@zip.js/zip.js" "^2.7.48" From 1d42807c0f04c870ba5757f8fb2a534fd51897f2 Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Thu, 10 Oct 2024 12:53:58 -0400 Subject: [PATCH 20/22] fix misapplication of geckodriver package (accidentally deleted) [run ci] --- .../server/patches/geckodriver+4.5.1.patch | 370 ++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 packages/server/patches/geckodriver+4.5.1.patch diff --git a/packages/server/patches/geckodriver+4.5.1.patch b/packages/server/patches/geckodriver+4.5.1.patch new file mode 100644 index 000000000000..f8c6b8cd0132 --- /dev/null +++ b/packages/server/patches/geckodriver+4.5.1.patch @@ -0,0 +1,370 @@ +diff --git a/node_modules/geckodriver/AUTHORS b/node_modules/geckodriver/AUTHORS +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/LICENSE b/node_modules/geckodriver/LICENSE +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/README.md b/node_modules/geckodriver/README.md +deleted file mode 100644 +index 95e3ef0..0000000 +--- a/node_modules/geckodriver/README.md ++++ /dev/null +@@ -1,239 +0,0 @@ +-Geckodriver [![CI](https://github.com/webdriverio-community/node-geckodriver/actions/workflows/ci.yml/badge.svg)](https://github.com/webdriverio-community/node-geckodriver/actions/workflows/ci.yml) [![Audit](https://github.com/webdriverio-community/node-geckodriver/actions/workflows/audit.yml/badge.svg)](https://github.com/webdriverio-community/node-geckodriver/actions/workflows/audit.yml) +-========== +- +-An NPM wrapper for Mozilla's [Geckodriver](https://github.com/mozilla/geckodriver). It manages to download various (or the latest) Geckodriver versions and provides a programmatic interface to start and stop it within Node.js. __Note:__ this is a wrapper module. If you discover any bugs with Geckodriver, please report them in the [official repository](https://github.com/mozilla/geckodriver). +- +-# Installing +- +-You can install this package via: +- +-```sh +-npm install geckodriver +-``` +- +-Or install it globally: +- +-```sh +-npm install -g geckodriver +-``` +- +-__Note:__ This installs a `geckodriver` shell script that runs the executable, but on Windows, [`selenium-webdriver`](https://www.npmjs.com/package/selenium-webdriver) looks for `geckodriver.exe`. To use a global installation of this package with [`selenium-webdriver`](https://www.npmjs.com/package/selenium-webdriver) on Windows, copy or link `geckodriver.exe` to a location on your `PATH` (such as the NPM bin directory) after installing this package: +- +-```sh +-mklink %USERPROFILE%\AppData\Roaming\npm\geckodriver.exe %USERPROFILE%\AppData\Roaming\npm\node_modules\geckodriver\geckodriver.exe +-``` +- +-Once installed you can start Geckodriver via: +- +-```sh +-npx geckodriver --port=4444 +-``` +- +-By default, this package downloads Geckodriver when used for the first time through the CLI or the programmatic interface. If you like to download it as part of the NPM install process, set the `GECKODRIVER_AUTO_INSTALL` environment flag, e.g.: +- +-```sh +-GECKODRIVER_AUTO_INSTALL=1 npm i +-``` +- +-To get a list of available CLI options run `npx geckodriver --help`. By default, this package downloads the latest version of the driver. If you prefer to have it install a custom Geckodriver version you can define the environment variable `GECKODRIVER_VERSION` when running in CLI, e.g.: +- +-```sh +-$ npm i geckodriver +-$ GECKODRIVER_VERSION="0.31.0" npx geckodriver --version +-geckodriver 0.31.0 (b617178ef491 2022-04-06 11:57 +0000) +- +-The source code of this program is available from +-testing/geckodriver in https://hg.mozilla.org/mozilla-central. +- +-This program is subject to the terms of the Mozilla Public License 2.0. +-You can obtain a copy of the license at https://mozilla.org/MPL/2.0/. +-``` +- +-## Setting a CDN URL for binary download +- +-To set an alternate CDN location for Geckodriver binaries, set the `GECKODRIVER_CDNURL` like this: +- +-```sh +-GECKODRIVER_CDNURL=https://INTERNAL_CDN/geckodriver/download +-``` +- +-Binaries on your CDN should be located in a subdirectory of the above base URL. For example, `/vxx.xx.xx/*.tar.gz` should be located under `/geckodriver/download` above. +- +-Alternatively, you can add the same property to your .npmrc file. +- +-The default location is set to https://github.com/mozilla/geckodriver/releases/download +- +-## Setting a PROXY URL +- +-Use `HTTPS_PROXY` or `HTTP_PROXY` to set your proxy URL. +- +-# Programmatic Interface +- +-You can import this package with Node.js and start the driver as part of your script and use it e.g. with [WebdriverIO](https://webdriver.io). +- +-## Exported Methods +- +-The package exports a `start` and `download` method. +- +-### `start` +- +-Starts a Geckodriver instance and returns a [`ChildProcess`](https://nodejs.org/api/child_process.html#class-childprocess). If Geckodriver is not downloaded it will download it for you. +- +-__Params:__ `GeckodriverParameters` - options to pass into Geckodriver (see below) +- +-__Example:__ +- +-```js +-import { start } from 'geckodriver'; +-import { remote } from 'webdriverio'; +-import waitPort from 'wait-port'; +- +-/** +- * first start Geckodriver +- */ +-const cp = await start({ port: 4444 }); +- +-/** +- * wait for Geckodriver to be up +- */ +-await waitPort({ port: 4444 }); +- +-/** +- * then start WebdriverIO session +- */ +-const browser = await remote({ capabilities: { browserName: 'firefox' } }); +-await browser.url('https://webdriver.io'); +-console.log(await browser.getTitle()); // prints "WebdriverIO · Next-gen browser and mobile automation test framework for Node.js | WebdriverIO" +- +-/** +- * kill Geckodriver process +- */ +-cp.kill(); +-``` +- +-__Note:__ as you can see in the example above this package does not wait for the driver to be up, you have to manage this yourself through packages like [`wait-on`](https://github.com/jeffbski/wait-on). +- +-### `download` +- +-Method to download a Geckodriver with a particular version. If a version parameter is omitted it tries to download the latest available version of the driver. +- +-__Params:__ `string` - version of Geckodriver to download (optional) +- +-## CJS Support +- +-In case your module uses CJS you can use this package as follows: +- +-```js +-const { start } = require('geckodriver') +-// see example above +-``` +- +-## Options +- +-The `start` method offers the following options to be passed on to the actual Geckodriver CLI. +- +-### `allowHosts` +- +-List of host names to allow. By default, the value of --host is allowed, and in addition, if that's a well-known local address, other variations on well-known local addresses are allowed. If --allow-hosts is provided only exactly those hosts are allowed. +- +-Type: `string[]`
+-Default: `[]` +- +-### `allowOrigins` +-List of request origins to allow. These must be formatted as `scheme://host:port`. By default, any request with an origin header is rejected. If `--allow-origins` is provided then only exactly those origins are allowed. +- +-Type: `string[]`
+-Default: `[]` +- +-### `binary` +-Path to the Firefox binary. +- +-Type: `string` +- +-### `connectExisting` +-Connect to an existing Firefox instance. +- +-Type: `boolean`
+-Default: `false` +- +-### `host` +-Host IP to use for WebDriver server. +- +-Type: `string`
+-Default: `0.0.0.0` +- +-### `jsdebugger` +-Attach browser toolbox debugger for Firefox. +- +-Type: `boolean`
+-Default: `false` +- +-### `log` +-Set Gecko log level [possible values: `fatal`, `error`, `warn`, `info`, `config`, `debug`, `trace`]. +- +-Type: `string` +- +-### `logNoTruncated` +-Write server log to file instead of stderr, increases log level to `INFO`. +- +-Type: `boolean` +- +-### `marionetteHost` +-Host to use to connect to Gecko. +- +-Type: `boolean`
+-Default: `127.0.0.1` +- +-### `marionettePort` +-Port to use to connect to Gecko. +- +-Type: `number`
+-Default: `0` +- +-### `port` +-Port to listen on. +- +-Type: `number` +- +-### `profileRoot` +-Directory in which to create profiles. Defaults to the system temporary directory. +- +-Type: `string` +- +-### `geckoDriverVersion` +-A version of Geckodriver to start. See https://github.com/mozilla/geckodriver/releases for all available versions, platforms and architecture. +- +-Type: `string` +- +-### `customGeckoDriverPath` +-Don't download Geckodriver, instead use a custom path to it, e.g. a cached binary. +- +-Type: `string`
+-Default: `process.env.GECKODRIVER_PATH` +- +-### `cacheDir` +-The path to the root of the cache directory. +- +-Type: `string`
+-Default: `process.env.GECKODRIVER_CACHE_DIR || os.tmpdir()` +- +-### `spawnOpts` +-Options to pass into the geckodriver process. This can be useful if needing +-Firefox to spawn with `MOZ_` prefix variables, such as `MOZ_HEADLESS_WIDTH`. +-See https://nodejs.org/api/child_process.html#child_processspawncommand-args-options for +-all options. +- +-Type: `SpawnOptionsWithoutStdio | SpawnOptionsWithStdioTuple`
+-Default: `undefined` +- +-# Other Browser Driver +- +-If you also look for other browser driver NPM wrappers, you can find them here: +- +-- Chrome: [giggio/node-chromedriver](https://github.com/giggio/node-chromedriver) +-- Microsoft Edge: [webdriverio-community/node-edgedriver](https://github.com/webdriverio-community/node-edgedriver) +-- Safari: [webdriverio-community/node-safaridriver](https://github.com/webdriverio-community/node-safaridriver) +- +---- +- +-For more information on WebdriverIO see the [homepage](https://webdriver.io). +diff --git a/node_modules/geckodriver/dist/cjs/index.d.ts b/node_modules/geckodriver/dist/cjs/index.d.ts +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/cjs/index.d.ts.map b/node_modules/geckodriver/dist/cjs/index.d.ts.map +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/cjs/index.js b/node_modules/geckodriver/dist/cjs/index.js +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/cjs/index.js.map b/node_modules/geckodriver/dist/cjs/index.js.map +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/cli.d.ts b/node_modules/geckodriver/dist/cli.d.ts +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/cli.d.ts.map b/node_modules/geckodriver/dist/cli.d.ts.map +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/cli.js b/node_modules/geckodriver/dist/cli.js +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/cli.js.map b/node_modules/geckodriver/dist/cli.js.map +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/constants.d.ts b/node_modules/geckodriver/dist/constants.d.ts +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/constants.d.ts.map b/node_modules/geckodriver/dist/constants.d.ts.map +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/constants.js b/node_modules/geckodriver/dist/constants.js +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/constants.js.map b/node_modules/geckodriver/dist/constants.js.map +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/index.d.ts b/node_modules/geckodriver/dist/index.d.ts +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/index.d.ts.map b/node_modules/geckodriver/dist/index.d.ts.map +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/index.js b/node_modules/geckodriver/dist/index.js +old mode 100644 +new mode 100755 +index 2edc6d2..d0b456e +--- a/node_modules/geckodriver/dist/index.js ++++ b/node_modules/geckodriver/dist/index.js +@@ -1,10 +1,14 @@ + import cp from 'node:child_process'; + import logger from '@wdio/logger'; ++import debugModule from 'debug' + import { download as downloadDriver } from './install.js'; + import { hasAccess, parseParams } from './utils.js'; + import { DEFAULT_HOSTNAME } from './constants.js'; + const log = logger('geckodriver'); + export async function start(params) { ++ // wrap in cypress debugger statement to avoid extraneous messages to the console ++ log.setLevel(debugModule.enabled('cypress-verbose:server:browsers:geckodriver') ? 'info' : 'silent') ++ + const { cacheDir, customGeckoDriverPath, spawnOpts, ...startArgs } = params; + let geckoDriverPath = (customGeckoDriverPath || + process.env.GECKODRIVER_PATH || +diff --git a/node_modules/geckodriver/dist/index.js.map b/node_modules/geckodriver/dist/index.js.map +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/install.d.ts b/node_modules/geckodriver/dist/install.d.ts +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/install.d.ts.map b/node_modules/geckodriver/dist/install.d.ts.map +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/install.js b/node_modules/geckodriver/dist/install.js +old mode 100644 +new mode 100755 +index c27c805..ac53518 +--- a/node_modules/geckodriver/dist/install.js ++++ b/node_modules/geckodriver/dist/install.js +@@ -70,6 +70,8 @@ async function downloadZip(res, cacheDir) { + * download on install + */ + if (process.argv[1] && process.argv[1].endsWith('/dist/install.js') && process.env.GECKODRIVER_AUTO_INSTALL) { +- await download().then(() => log.info('Success!'), (err) => log.error(`Failed to install Geckodriver: ${err.stack}`)); ++ // removing the await here as packherd cannot bundle with a top-level await. ++ // This only has an impact if invoking from a CLI context, which cypress is not. ++ download().then(() => log.info('Success!'), (err) => log.error(`Failed to install Geckodriver: ${err.stack}`)); + } + //# sourceMappingURL=install.js.map +\ No newline at end of file +diff --git a/node_modules/geckodriver/dist/install.js.map b/node_modules/geckodriver/dist/install.js.map +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/types.d.ts b/node_modules/geckodriver/dist/types.d.ts +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/types.d.ts.map b/node_modules/geckodriver/dist/types.d.ts.map +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/types.js b/node_modules/geckodriver/dist/types.js +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/types.js.map b/node_modules/geckodriver/dist/types.js.map +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/utils.d.ts b/node_modules/geckodriver/dist/utils.d.ts +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/utils.d.ts.map b/node_modules/geckodriver/dist/utils.d.ts.map +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/utils.js b/node_modules/geckodriver/dist/utils.js +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/dist/utils.js.map b/node_modules/geckodriver/dist/utils.js.map +old mode 100644 +new mode 100755 +diff --git a/node_modules/geckodriver/tsconfig.tsbuildinfo b/node_modules/geckodriver/tsconfig.tsbuildinfo +old mode 100644 +new mode 100755 From 00de09a7d1a8ee9cea5fbd033d4c41418e272193 Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Fri, 11 Oct 2024 08:52:07 -0400 Subject: [PATCH 21/22] empty commit to trigger ci [run ci] From e8ab563b783292c1d2b54201ea5e5f4b54bbbd99 Mon Sep 17 00:00:00 2001 From: AtofStryker Date: Fri, 11 Oct 2024 13:53:52 -0400 Subject: [PATCH 22/22] address comments from code review [run ci] --- packages/server/lib/browsers/firefox.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/server/lib/browsers/firefox.ts b/packages/server/lib/browsers/firefox.ts index 122e46d7d4bf..6f0a85efcc03 100644 --- a/packages/server/lib/browsers/firefox.ts +++ b/packages/server/lib/browsers/firefox.ts @@ -463,7 +463,7 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc const profileDir = utils.getProfileDir(browser, options.isTextTerminal) - // Delete the profile directory if in open mode. + // Delete the legacy profile directory if in open mode. // Cypress does this because profiles are sourced and created differently with geckodriver/webdriver. // the profile creation method before 13.15.0 will no longer work with geckodriver/webdriver // and actually corrupts the profile directory from being able to be encoded. Hence, we delete it to prevent any conflicts. @@ -513,9 +513,9 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc // However, since Cypress 13.15.1, // geckodriver creates unique profile names that copy over the xulstore.json to the used profile. // The copy is ultimately updated on the unique profile name and is destroyed when the browser is torn down, - // so the values are not persisted. Cypress could hypothetically determine the profile in use, copy the xulstore.json + // so the values are not persisted. Cypress could hypothetically determine the profile is in use, copy the xulstore.json // out of the profile and try to persist it in the next created profile, but this method is likely error prone as it requires - // moving/copying of files while creation/deletion of profiles occur, plus the ability to coorelate the correct profile to the current run, + // moving/copying of files while creation/deletion of profiles occur, plus the ability to correlate the correct profile to the current run, // which there are not guarantees we can deterministically do this in open mode. const sizemode = 'maximized' @@ -592,7 +592,7 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc browserInstanceWrapper.kill = () => undefined try { - /** + /** * To set the profile, we use the profile capabilities in firefoxOptions which * requires the profile to be base64 encoded. The profile will be copied over to whatever * profile is created by geckodriver stemming from the root profile path.