From 54127e3c61f6b3ffd949c1f1deed32e81d6d3b93 Mon Sep 17 00:00:00 2001 From: Mike McCready <66998419+MikeMcC399@users.noreply.github.com> Date: Thu, 20 Jun 2024 23:03:27 +0200 Subject: [PATCH 01/10] dependency: update tmp to 0.2.3 (#29696) * dependency: update tmp to 0.2.3 * Update changelog * Update cli/CHANGELOG.md --------- Co-authored-by: Jennifer Shehane Co-authored-by: Matt Schile --- cli/CHANGELOG.md | 3 ++- cli/package.json | 2 +- yarn.lock | 10 ++++------ 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 5c5c9740bb40..bb6add94ed49 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -5,6 +5,7 @@ _Released 7/2/2024 (PENDING)_ **Dependency Updates:** +- Updated `tmp` from `0.2.1` to `0.2.3`. Addresses [#29693](https://github.com/cypress-io/cypress/issues/29693). - Updated `ws` from `5.2.3` to `5.2.4`. Addressed in [#29698](https://github.com/cypress-io/cypress/pull/29698). ## 13.12.0 @@ -23,7 +24,7 @@ _Released 6/18/2024_ - When capture protocol script fails verification, an appropriate error is now displayed. Previously, an error regarding Test Replay archive location was shown. Addressed in [#29603](https://github.com/cypress-io/cypress/pull/29603). - Fixed an issue where receiving HTTP responses with invalid headers raised an error. Now cypress removes the invalid headers and gives a warning in the console with debug mode on. Fixes [#28865](https://github.com/cypress-io/cypress/issues/28865). -**Misc:** +**Misc:** - Report afterSpec durations to Cloud API when running in record mode with Test Replay enabled. Addressed in [#29500](https://github.com/cypress-io/cypress/pull/29500). diff --git a/cli/package.json b/cli/package.json index 3be49c693957..da1d58a4afe2 100644 --- a/cli/package.json +++ b/cli/package.json @@ -59,7 +59,7 @@ "request-progress": "^3.0.0", "semver": "^7.5.3", "supports-color": "^8.1.1", - "tmp": "~0.2.1", + "tmp": "~0.2.3", "untildify": "^4.0.0", "yauzl": "^2.10.0" }, diff --git a/yarn.lock b/yarn.lock index a2cf08980893..de40c3594025 100644 --- a/yarn.lock +++ b/yarn.lock @@ -30007,12 +30007,10 @@ tmp@0.0.33, tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" -tmp@^0.2.0, tmp@^0.2.1, tmp@~0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" - integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== - dependencies: - rimraf "^3.0.0" +tmp@^0.2.0, tmp@^0.2.1, tmp@~0.2.1, tmp@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" + integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== to-absolute-glob@^2.0.0: version "2.0.2" From 8217fdcd14417c82b6472896483f1c456a923bc9 Mon Sep 17 00:00:00 2001 From: Bill Glesias Date: Fri, 21 Jun 2024 11:37:09 -0400 Subject: [PATCH 02/10] fix: add remote.active-protocols argument and set it to 2 to enable CDP (#29720) --- cli/CHANGELOG.md | 4 ++++ packages/server/lib/browsers/firefox.ts | 6 ++++++ .../server/test/unit/browsers/firefox_spec.ts | 17 +++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index bb6add94ed49..b6f1a1d2e274 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -3,6 +3,10 @@ _Released 7/2/2024 (PENDING)_ +**Bugfixes:** + +- Fixed an issue where Firefox 129 (Firefox Nightly) would not launch with Cypress. Fixes [#29713](https://github.com/cypress-io/cypress/issues/29713). Fixed in [#29720](https://github.com/cypress-io/cypress/pull/29720). + **Dependency Updates:** - Updated `tmp` from `0.2.1` to `0.2.3`. Addresses [#29693](https://github.com/cypress-io/cypress/issues/29693). diff --git a/packages/server/lib/browsers/firefox.ts b/packages/server/lib/browsers/firefox.ts index b4c4f01543b9..8d78cf89da4b 100644 --- a/packages/server/lib/browsers/firefox.ts +++ b/packages/server/lib/browsers/firefox.ts @@ -199,6 +199,12 @@ const defaultPreferences = { 'privacy.trackingprotection.enabled': false, + // CDP is deprecated in Firefox 129 and up. + // In order to enable CDP, we need to set + // 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 + 'remote.active-protocols': 2, // Enable Remote Agent // https://bugzilla.mozilla.org/show_bug.cgi?id=1544393 'remote.enabled': true, diff --git a/packages/server/test/unit/browsers/firefox_spec.ts b/packages/server/test/unit/browsers/firefox_spec.ts index 1f29702ab50c..40ea67b85ed4 100644 --- a/packages/server/test/unit/browsers/firefox_spec.ts +++ b/packages/server/test/unit/browsers/firefox_spec.ts @@ -334,6 +334,23 @@ describe('lib/browsers/firefox', () => { }) }) + // CDP is deprecated in Firefox 129 and up. + // In order to enable CDP, we need to set + // 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 () { + 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) + }) + }) + it('updates the preferences', function () { return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { expect(FirefoxProfile.prototype.updatePreferences).to.be.called From f6c52d6f1d9e2c485091e1b4120fd8cbc3bf712d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 11:37:47 -0400 Subject: [PATCH 03/10] chore: Update v8 snapshot cache (#29715) * chore: updating v8 snapshot cache * chore: updating v8 snapshot cache * chore: updating v8 snapshot cache * chore: updating v8 snapshot cache * chore: updating v8 snapshot cache --------- Co-authored-by: cypress-bot[bot] <+cypress-bot[bot]@users.noreply.github.com> --- tooling/v8-snapshot/cache/darwin/snapshot-meta.json | 2 +- tooling/v8-snapshot/cache/linux/snapshot-meta.json | 2 +- tooling/v8-snapshot/cache/win32/snapshot-meta.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tooling/v8-snapshot/cache/darwin/snapshot-meta.json b/tooling/v8-snapshot/cache/darwin/snapshot-meta.json index 46b7d2711166..d0ff6b3706a7 100644 --- a/tooling/v8-snapshot/cache/darwin/snapshot-meta.json +++ b/tooling/v8-snapshot/cache/darwin/snapshot-meta.json @@ -4351,5 +4351,5 @@ "./tooling/v8-snapshot/cache/darwin/snapshot-entry.js" ], "deferredHashFile": "yarn.lock", - "deferredHash": "d5fba40067187d94123f2436aff67aba7a4e35da015285bf93f7ed5dce895c0a" + "deferredHash": "06ab0f779d9783d6e6de1392b884bcac67e5526dc117399eb194b13ccbc8f51d" } \ No newline at end of file diff --git a/tooling/v8-snapshot/cache/linux/snapshot-meta.json b/tooling/v8-snapshot/cache/linux/snapshot-meta.json index eca225b2e228..1166956bf6b1 100644 --- a/tooling/v8-snapshot/cache/linux/snapshot-meta.json +++ b/tooling/v8-snapshot/cache/linux/snapshot-meta.json @@ -4354,5 +4354,5 @@ "./tooling/v8-snapshot/cache/linux/snapshot-entry.js" ], "deferredHashFile": "yarn.lock", - "deferredHash": "d5fba40067187d94123f2436aff67aba7a4e35da015285bf93f7ed5dce895c0a" + "deferredHash": "06ab0f779d9783d6e6de1392b884bcac67e5526dc117399eb194b13ccbc8f51d" } \ No newline at end of file diff --git a/tooling/v8-snapshot/cache/win32/snapshot-meta.json b/tooling/v8-snapshot/cache/win32/snapshot-meta.json index cba618fe9ded..d1592395f7bd 100644 --- a/tooling/v8-snapshot/cache/win32/snapshot-meta.json +++ b/tooling/v8-snapshot/cache/win32/snapshot-meta.json @@ -4354,5 +4354,5 @@ "./tooling/v8-snapshot/cache/win32/snapshot-entry.js" ], "deferredHashFile": "yarn.lock", - "deferredHash": "a27445b4e6f78b88b330f7cbba52043d593c3514a37c92380a12dfe1e7e2c330" + "deferredHash": "31caf568daf8489a1120ddc2bdedb40ae73798571f0e96f716e033a1b45ce744" } \ No newline at end of file From af2b764815605d00ce082b8d6e37d7cd73ee70dd Mon Sep 17 00:00:00 2001 From: Bill Glesias Date: Fri, 21 Jun 2024 13:27:06 -0400 Subject: [PATCH 04/10] fix: chrome missing CRI client after browser relaunch (#29663) * reprod browser cri crash chrome * commit with the fix * Add integration-like test that verifies the browser is launched with the correct arguments [run ci] --- cli/CHANGELOG.md | 6 +- .../data-context/src/data/coreDataShape.ts | 2 + packages/server/lib/browsers/index.ts | 5 + packages/server/lib/modes/run.ts | 8 + packages/server/test/integration/run_spec.ts | 163 ++++++++++++++++++ .../test/unit/browsers/browsers_spec.js | 25 +++ 6 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 packages/server/test/integration/run_spec.ts diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index b6f1a1d2e274..9e62d583b56c 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -1,7 +1,11 @@ ## 13.12.1 -_Released 7/2/2024 (PENDING)_ +_Released 7/02/2024 (PENDING)_ + +**Bugfixes:** + +- Fixed an issue where Chrome launch instances would not recreate the browser CRI client correctly after recovering from an unexpected browser closure. Fixes [#27657](https://github.com/cypress-io/cypress/issues/27657). Fixed in [#29663](https://github.com/cypress-io/cypress/pull/29663). **Bugfixes:** diff --git a/packages/data-context/src/data/coreDataShape.ts b/packages/data-context/src/data/coreDataShape.ts index d14d17cfedb6..0a470cd132e5 100644 --- a/packages/data-context/src/data/coreDataShape.ts +++ b/packages/data-context/src/data/coreDataShape.ts @@ -171,6 +171,7 @@ export interface CoreDataShape { } | null cloudProject: CloudDataShape eventCollectorSource: EventCollectorSource | null + didBrowserPreviouslyHaveUnexpectedExit: boolean } /** @@ -251,6 +252,7 @@ export function makeCoreData (modeOptions: Partial = {}): CoreDa testsForRunResults: {}, }, eventCollectorSource: null, + didBrowserPreviouslyHaveUnexpectedExit: false, } async function machineId (): Promise { diff --git a/packages/server/lib/browsers/index.ts b/packages/server/lib/browsers/index.ts index 59e9b3f8e4f5..124060e6b579 100644 --- a/packages/server/lib/browsers/index.ts +++ b/packages/server/lib/browsers/index.ts @@ -222,6 +222,11 @@ export = { // so that there is a default for each browser but // enable the browser to configure the interface instance.once('exit', async (code, signal) => { + // When the browser has unexpectedly exited, we need to send a signal to the attempt launcher to recreate the browser CRI clients. + // We do NOT want to attempt to use existing CRI clients as the previous instance of the browser was terminated. + // @see https://github.com/cypress-io/cypress/issues/27657 + ctx.coreData.didBrowserPreviouslyHaveUnexpectedExit = true + debug('browser instance exit event received %o', { code, signal }) ctx.actions.app.setBrowserStatus('closed') diff --git a/packages/server/lib/modes/run.ts b/packages/server/lib/modes/run.ts index 25ebd1c376fd..66a626057e64 100644 --- a/packages/server/lib/modes/run.ts +++ b/packages/server/lib/modes/run.ts @@ -482,6 +482,14 @@ async function waitForBrowserToConnect (options: { project: Project, socketId: s debug('waiting for socket to connect and browser to launch...') + const coreData = require('@packages/data-context').getCtx().coreData + + if (coreData.didBrowserPreviouslyHaveUnexpectedExit) { + debug(`browser previously exited. Setting shouldLaunchNewTab=false to recreate the correct browser automation clients.`) + options.shouldLaunchNewTab = false + coreData.didBrowserPreviouslyHaveUnexpectedExit = false + } + return Bluebird.all([ waitForSocketConnection(project, socketId), // TODO: remove the need to extend options and coerce this type diff --git a/packages/server/test/integration/run_spec.ts b/packages/server/test/integration/run_spec.ts new file mode 100644 index 000000000000..c4f3e91c1f1c --- /dev/null +++ b/packages/server/test/integration/run_spec.ts @@ -0,0 +1,163 @@ +import fs from 'fs' +import fsExtra from 'fs-extra' +import { run } from '../../lib/modes/run' +import { ProjectConfigIpc } from '@packages/data-context/src/data/ProjectConfigIpc' +import { FileDataSource } from '@packages/data-context/src/sources/FileDataSource' +import browserUtils from '../../lib/browsers' +import { fs as fsUtil } from '../../lib/util/fs' +import { getCtx } from '../../lib/makeDataContext' +import { OpenProject } from '../../lib/open_project' + +describe('lib/modes/run', () => { + let browserConnectTimeoutPlaceholder + let ctx + let specs = ['foo.cy.ts', 'bar.cy.ts', 'baz.cy.ts'] + let options = { + autoCancelAfterFailures: undefined, + browser: 'chrome', + ciBuildId: undefined, + exit: false, + group: undefined, + headed: false, + key: undefined, + outputPath: '', + parallel: undefined, + projectRoot: '/path/to/project/root', + quiet: false, + record: false, + socketId: 'foobarbaz', + spec: specs, + tag: undefined, + testingType: 'e2e', + webSecurity: true, + } + + beforeEach(() => { + browserConnectTimeoutPlaceholder = process.env.CYPRESS_INTERNAL_BROWSER_CONNECT_TIMEOUT + process.env.CYPRESS_INTERNAL_BROWSER_CONNECT_TIMEOUT = '2000' + specs = ['foo.cy.ts', 'bar.cy.ts', 'baz.cy.ts'] + + options = { + autoCancelAfterFailures: undefined, + browser: 'chrome', + ciBuildId: undefined, + exit: false, + group: undefined, + headed: false, + key: undefined, + onError: (err: Error) => undefined, + outputPath: '', + parallel: undefined, + projectRoot: '/path/to/project/root', + quiet: false, + record: false, + socketId: 'foobarbaz', + spec: specs, + tag: undefined, + testingType: 'e2e', + webSecurity: true, + } + + const mockedRelativeSupportFilePath = 'cypress/support/e2e.js' + + const chromeStable = { + displayName: 'Chrome', + name: 'chrome', + channel: 'stable', + version: '12.34.56', + majorVersion: '12', + family: 'chromium', + path: '/path/to/google-chrome', + } + + const foundBrowsers = [ + chromeStable, + ] + + sinon.stub(browserUtils, 'get').resolves(foundBrowsers) + sinon.stub(browserUtils, 'removeOldProfiles').resolves() + + sinon.stub(fsUtil, 'access').withArgs(options.projectRoot).resolves() + sinon.stub(process, 'chdir').withArgs(options.projectRoot).returns() + // @ts-expect-error + sinon.stub(fs, 'statSync').withArgs(options.projectRoot).returns({ + isDirectory: () => true, + }) + + // @ts-expect-error + sinon.stub(fsExtra, 'pathExists').withArgs(`${options.projectRoot}/${mockedRelativeSupportFilePath}`).resolves(true) + /// mock the project config IPC loadConfig to avoid communicating over sub processes, which will not work here since we are mocking the directory + // @ts-expect-error + sinon.stub(ProjectConfigIpc.prototype, 'loadConfig').callsFake(() => { + return Promise.resolve({ + requires: [], + initialConfig: '{}', + }) + }) + + sinon.stub(FileDataSource.prototype, 'getFilesByGlob').withArgs(options.projectRoot, 'cypress/support/e2e.{js,jsx,ts,tsx}').resolves([`${options.projectRoot}/${mockedRelativeSupportFilePath}`]) + + ctx = getCtx() + + ctx.coreData.machineBrowsers = Promise.resolve(foundBrowsers) + ctx.project._specs = specs + + // mock the websocket connection + globalThis.CY_TEST_MOCK = { + waitForSocketConnection: true, + listenForProjectEnd: { stats: { failures: 0 } }, + } + }) + + afterEach(() => { + delete globalThis['CY_TEST_MOCK'] + process.env.CYPRESS_INTERNAL_BROWSER_CONNECT_TIMEOUT = browserConnectTimeoutPlaceholder + }) + + it('recovers when the browser is closed unexpectedly by not sending "shouldLaunchNewTab" on newly created browser instances (creates the CRI client in the actual implementation)', async () => { + let launchAttemptOfBarSpec = 0 + + // @ts-expect-error + sinon.stub(OpenProject.prototype, 'launch').callsFake((_browser, spec, browserOpts) => { + switch (spec as unknown as string) { + case 'foo.cy.ts': + // should be a fresh launch of the browser, so shouldLaunchNewTab should be false + expect(browserOpts.shouldLaunchNewTab).to.equal(false) + // pass the first spec + + return Promise.resolve() + case 'bar.cy.ts': + launchAttemptOfBarSpec++ + if (launchAttemptOfBarSpec === 1) { + // we are on our first launch of the browser. We are going to mock + // the browser unexpectedly closing out of our control + expect(ctx.coreData.didBrowserPreviouslyHaveUnexpectedExit).to.equal(false) + // since this is not the first spec launched in the browser, we should launch with a new tab and NOT a new browser instance + expect(browserOpts.shouldLaunchNewTab).to.equal(true) + + // mock unexpected close of browser in second spec + // return nothing as this promise should never resolve + ctx.coreData.didBrowserPreviouslyHaveUnexpectedExit = true + + return new Promise(((resolve) => { + // never resolves as we are mocking the browser unexpectedly closing + })) + } + + // assume we are second launch attempt or later. We should have detected that the browser + // previously exited and that we need to recreate everything related to the instance, so + // shouldLaunchNewTab should be false + expect(ctx.coreData.didBrowserPreviouslyHaveUnexpectedExit).to.equal(false) + expect(browserOpts.shouldLaunchNewTab).to.equal(false) + + return Promise.resolve() + case 'baz.cy.ts': + return Promise.resolve() + default: + return Promise.resolve() + } + }) + + await run(options, Promise.resolve()) + }) +}) diff --git a/packages/server/test/unit/browsers/browsers_spec.js b/packages/server/test/unit/browsers/browsers_spec.js index cf0a787cb441..f9ea47278168 100644 --- a/packages/server/test/unit/browsers/browsers_spec.js +++ b/packages/server/test/unit/browsers/browsers_spec.js @@ -399,6 +399,31 @@ describe('lib/browsers/index', () => { }) }) }) + + context('didBrowserPreviouslyHaveUnexpectedExit', () => { + it('sets didBrowserPreviouslyHaveUnexpectedExit when the browser unexpectedly closes', () => { + const url = 'http://localhost:3000' + const ee = new EventEmitter() + + ee.kill = () => { + ee.emit('exit') + } + + const instance = ee + + browsers._setInstance(instance) + + sinon.stub(electron, 'open').resolves(instance) + sinon.spy(ctx.actions.app, 'setBrowserStatus') + + // Stub to speed up test, we don't care about the delay + sinon.stub(Promise, 'delay').resolves() + + return browsers.open({ name: 'electron', family: 'chromium' }, { url }, null, ctx).then(browsers.close).then(() => { + expect(ctx.coreData.didBrowserPreviouslyHaveUnexpectedExit).eq(true) + }) + }) + }) }) // Ooo, browser clean up tests are disabled?!! From c4c3154d211d5d54a4b308925cb96e15dfd1fb3f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:34:48 -0400 Subject: [PATCH 05/10] chore: Update Chrome (beta) to 127.0.6533.17 (#29721) Co-authored-by: cypress-bot[bot] <41898282+cypress-bot[bot]@users.noreply.github.com> --- browser-versions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser-versions.json b/browser-versions.json index b41fed0f56eb..869be06018c0 100644 --- a/browser-versions.json +++ b/browser-versions.json @@ -1,5 +1,5 @@ { - "chrome:beta": "127.0.6533.4", + "chrome:beta": "127.0.6533.17", "chrome:stable": "126.0.6478.114", "chrome:minimum": "64.0.3282.0" } From a6b58a8b2ff10801267e5aaf20c24ce97a395c1e Mon Sep 17 00:00:00 2001 From: Joost Koehoorn Date: Fri, 21 Jun 2024 21:24:42 +0200 Subject: [PATCH 06/10] perf: improve performance of `experimentalSourceRewriting` (#29540) * perf: improve performance of `experimentalSourceRewriting` This change is in addition to https://github.com/benjamn/recast/pull/1399. This commit focuses on Cypress' use of recast, with the following optimizations: 1. Avoid printing the source file again if no change was made. Printing an AST using recast does reuse the original text, but identifying for which parts of the AST reuse is possible comes with noticeable overhead. By tracking changes within the visitor it becomes possible to skip this phase entirely if no changes were made. 2. Avoid a scope lookup (`path.scope.declares(node.name)`) for all identifiers in the program, doing it only for identifiers that may have to be rewritten. With these changes, a 2.6MB bundle that does not need rewriting has improved from 4.4s to 2.3s, provided that the above-mentioned recast PR has been applied. * chore: move `experimentalSourceRewriting` release note to pending release section --------- Co-authored-by: Bill Glesias Co-authored-by: Jennifer Shehane --- cli/CHANGELOG.md | 4 +++ packages/rewriter/lib/js-rules.ts | 43 ++++++++++++++------------ packages/rewriter/lib/js.ts | 30 +++++++++++++++--- packages/rewriter/test/unit/js-spec.ts | 2 +- 4 files changed, 53 insertions(+), 26 deletions(-) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 9e62d583b56c..46fe84b9139a 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -7,6 +7,10 @@ _Released 7/02/2024 (PENDING)_ - Fixed an issue where Chrome launch instances would not recreate the browser CRI client correctly after recovering from an unexpected browser closure. Fixes [#27657](https://github.com/cypress-io/cypress/issues/27657). Fixed in [#29663](https://github.com/cypress-io/cypress/pull/29663). +**Performance:** + +- Improved performance of `experimentalSourceRewriting` option. Fixed in [#29540](https://github.com/cypress-io/cypress/pull/29540). + **Bugfixes:** - Fixed an issue where Firefox 129 (Firefox Nightly) would not launch with Cypress. Fixes [#29713](https://github.com/cypress-io/cypress/issues/29713). Fixed in [#29720](https://github.com/cypress-io/cypress/pull/29720). diff --git a/packages/rewriter/lib/js-rules.ts b/packages/rewriter/lib/js-rules.ts index bc8d05e5fe88..ddd2fb369130 100644 --- a/packages/rewriter/lib/js-rules.ts +++ b/packages/rewriter/lib/js-rules.ts @@ -62,6 +62,8 @@ function resolveLocationReference () { ) } +const replaceableProps = ['parent', 'top', 'location'] + /** * Given an Identifier or a Literal, return a property name that should use `resolveWindowReference`. * @param node @@ -70,12 +72,12 @@ function getReplaceablePropOfMemberExpression (node: n.MemberExpression) { const { property } = node // something.(top|parent) - if (n.Identifier.check(property) && ['parent', 'top', 'location'].includes(property.name)) { + if (n.Identifier.check(property) && replaceableProps.includes(property.name)) { return property.name } // something['(top|parent)'] - if (n.Literal.check(property) && ['parent', 'top', 'location'].includes(String(property.value))) { + if (n.Literal.check(property) && replaceableProps.includes(String(property.value))) { return String(property.value) } @@ -104,6 +106,7 @@ export const jsRules: Visitor<{}> = { } path.replace(resolveWindowReference(path.get('object').node, prop)) + this.reportChanged() return false }, @@ -120,6 +123,7 @@ export const jsRules: Visitor<{}> = { if (isAssignee && node.name === 'location') { // `location = 'something'`, rewrite to intercepted href setter since relative urls can break this path.replace(b.memberExpression(resolveLocationReference(), b.identifier('href'))) + this.reportChanged() return false } @@ -147,40 +151,38 @@ export const jsRules: Visitor<{}> = { } } - if (path.scope.declares(node.name)) { - // identifier has been declared in local scope, don't care about replacing + // identifier has been declared in local scope, don't care about replacing + if (!replaceableProps.includes(node.name) || path.scope.declares(node.name)) { return this.traverse(path) } - if (node.name === 'location') { - path.replace(resolveLocationReference()) - - return false - } + switch (node.name) { + case 'location': + path.replace(resolveLocationReference()) + this.reportChanged() - if (['parent', 'top'].includes(node.name)) { - path.replace(resolveWindowReference(globalIdentifier, node.name)) + return false + case 'parent': + case 'top': + path.replace(resolveWindowReference(globalIdentifier, node.name)) + this.reportChanged() - return false + return false + default: + return this.traverse(path) } - - this.traverse(path) }, visitAssignmentExpression (path) { const { node } = path - const finish = () => { - this.traverse(path) - } - if (!n.MemberExpression.check(node.left)) { - return finish() + return this.traverse(path) } const propBeingSet = getReplaceablePropOfMemberExpression(node.left) if (!propBeingSet) { - return finish() + return this.traverse(path) } if (node.operator !== '=') { @@ -194,6 +196,7 @@ export const jsRules: Visitor<{}> = { const objBeingSetOn = node.left.object path.replace(resolveWindowReference(objBeingSetOn, propBeingSet, node.right)) + this.reportChanged() return false }, diff --git a/packages/rewriter/lib/js.ts b/packages/rewriter/lib/js.ts index 3e2cb7c09f08..f32eae4ad70d 100644 --- a/packages/rewriter/lib/js.ts +++ b/packages/rewriter/lib/js.ts @@ -32,7 +32,13 @@ export function rewriteJsSourceMap (url: string, js: string, inputSourceMap: any const ast = recast.parse(js, { sourceFileName }) - astTypes.visit(ast, jsRules) + const visitor = astTypes.PathVisitor.fromMethodsObject(jsRules) + + visitor.visit(ast) + + if (!visitor.wasChangeReported() && inputSourceMap) { + return inputSourceMap + } return recast.print(ast, { inputSourceMap, @@ -50,18 +56,32 @@ export function rewriteJsSourceMap (url: string, js: string, inputSourceMap: any export function _rewriteJsUnsafe (url: string, js: string, deferSourceMapRewrite?: DeferSourceMapRewriteFn): string { const ast = recast.parse(js) + let didRewrite: boolean + try { - astTypes.visit(ast, jsRules) + const visitor = astTypes.PathVisitor.fromMethodsObject(jsRules) + + visitor.visit(ast) + + didRewrite = visitor.wasChangeReported() } catch (err: any) { // if visiting fails, it points to a bug in our rewriting logic, so raise the error to the driver return _generateDriverError(url, err) } - const { code } = recast.print(ast, defaultPrintOpts) + let rewritten: string + + if (didRewrite) { + const { code } = recast.print(ast, defaultPrintOpts) + + rewritten = code + } else { + rewritten = js + } if (!deferSourceMapRewrite) { // no sourcemaps - return sourceMaps.stripMappingUrl(code) + return sourceMaps.stripMappingUrl(rewritten) } // get an ID that can be used to lazy-generate the source map later @@ -71,7 +91,7 @@ export function _rewriteJsUnsafe (url: string, js: string, deferSourceMapRewrite // using a relative URL ensures that required cookies + other headers are sent along // and can be reused if the user's sourcemap requires an HTTP request to be made `/__cypress/source-maps/${sourceMapId}.map`, - code, + rewritten, ) } diff --git a/packages/rewriter/test/unit/js-spec.ts b/packages/rewriter/test/unit/js-spec.ts index 479642d936d7..640fb657cfb4 100644 --- a/packages/rewriter/test/unit/js-spec.ts +++ b/packages/rewriter/test/unit/js-spec.ts @@ -164,7 +164,7 @@ describe('js rewriter', function () { err.stack = 'stack' - sinon.stub(astTypes, 'visit').throws(err) + sinon.stub(astTypes.PathVisitor, 'fromMethodsObject').throws(err) const actual = _rewriteJsUnsafe(URL, 'console.log()') From eee25c3f07e9b67325cb2dba15e40f2c2c017e8e Mon Sep 17 00:00:00 2001 From: Bill Glesias Date: Mon, 24 Jun 2024 11:26:04 -0400 Subject: [PATCH 07/10] chore: condense bugfix sections and hoist performance section (#29728) --- cli/CHANGELOG.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 46fe84b9139a..bd663275de75 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -3,16 +3,13 @@ _Released 7/02/2024 (PENDING)_ -**Bugfixes:** - -- Fixed an issue where Chrome launch instances would not recreate the browser CRI client correctly after recovering from an unexpected browser closure. Fixes [#27657](https://github.com/cypress-io/cypress/issues/27657). Fixed in [#29663](https://github.com/cypress-io/cypress/pull/29663). - **Performance:** - Improved performance of `experimentalSourceRewriting` option. Fixed in [#29540](https://github.com/cypress-io/cypress/pull/29540). **Bugfixes:** +- Fixed an issue where Chrome launch instances would not recreate the browser CRI client correctly after recovering from an unexpected browser closure. Fixes [#27657](https://github.com/cypress-io/cypress/issues/27657). Fixed in [#29663](https://github.com/cypress-io/cypress/pull/29663). - Fixed an issue where Firefox 129 (Firefox Nightly) would not launch with Cypress. Fixes [#29713](https://github.com/cypress-io/cypress/issues/29713). Fixed in [#29720](https://github.com/cypress-io/cypress/pull/29720). **Dependency Updates:** From b1fb414aa1291e3956e55a98e5b8cab736eac205 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 11:26:24 -0400 Subject: [PATCH 08/10] chore: Update v8 snapshot cache (#29725) Co-authored-by: cypress-bot[bot] <+cypress-bot[bot]@users.noreply.github.com> --- tooling/v8-snapshot/cache/win32/snapshot-meta.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/v8-snapshot/cache/win32/snapshot-meta.json b/tooling/v8-snapshot/cache/win32/snapshot-meta.json index d1592395f7bd..1f68e1ed1f1a 100644 --- a/tooling/v8-snapshot/cache/win32/snapshot-meta.json +++ b/tooling/v8-snapshot/cache/win32/snapshot-meta.json @@ -4354,5 +4354,5 @@ "./tooling/v8-snapshot/cache/win32/snapshot-entry.js" ], "deferredHashFile": "yarn.lock", - "deferredHash": "31caf568daf8489a1120ddc2bdedb40ae73798571f0e96f716e033a1b45ce744" + "deferredHash": "24e8721c7d54ea44b96811cb7cdf309256441d2e605c48921d076c1547507c0e" } \ No newline at end of file From 80c2d447b0a0acd35a3150361b70de1afdce1823 Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Mon, 24 Jun 2024 13:59:34 -0400 Subject: [PATCH 09/10] chore(deps): add type-fest devDep (#29729) * chore: add type-fest devDep * empty commit --- packages/frontend-shared/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/frontend-shared/package.json b/packages/frontend-shared/package.json index 76c11d3e3a3b..f9e6f80f43b1 100644 --- a/packages/frontend-shared/package.json +++ b/packages/frontend-shared/package.json @@ -69,6 +69,7 @@ "postcss": "^8.4.22", "shiki": "^0.9.12", "tailwindcss": "^3.3.1", + "type-fest": "^2.3.4", "unplugin-icons": "0.19.0", "unplugin-vue-components": "^0.27.0", "vite": "5.2.11", From 7b07c75b19307bd8a328b41596c0008609a2c21e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 14:00:24 -0400 Subject: [PATCH 10/10] chore(deps): update dependency autoprefixer to v10.4.19 (#29724) * chore(deps): update dependency autoprefixer to v10.4.19 * empty commit --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Jennifer Shehane --- packages/frontend-shared/package.json | 2 +- packages/web-config/package.json | 2 +- yarn.lock | 48 +++++++++++---------------- 3 files changed, 22 insertions(+), 30 deletions(-) diff --git a/packages/frontend-shared/package.json b/packages/frontend-shared/package.json index f9e6f80f43b1..3f51ad696547 100644 --- a/packages/frontend-shared/package.json +++ b/packages/frontend-shared/package.json @@ -43,7 +43,7 @@ "@vue/compiler-sfc": "3.2.47", "@vue/test-utils": "2.3.2", "@vueuse/core": "7.2.2", - "autoprefixer": "^10.4.14", + "autoprefixer": "^10.4.19", "axe-core": "4.4.1", "browser-logos": "github:alrra/browser-logos", "combine-properties": "0.1.0", diff --git a/packages/web-config/package.json b/packages/web-config/package.json index 517720c4fc69..5e91b34746b6 100644 --- a/packages/web-config/package.json +++ b/packages/web-config/package.json @@ -17,7 +17,7 @@ "@types/webpack": "^5.28.1", "@types/webpack-dev-server": "^4.0.0", "arraybuffer-loader": "1.0.8", - "autoprefixer": "9.7.4", + "autoprefixer": "10.4.19", "babel-loader": "9.1.3", "browser-resolve": "2.0.0", "buffer": "6.0.3", diff --git a/yarn.lock b/yarn.lock index de40c3594025..041d36345096 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10333,27 +10333,14 @@ autobarrel@^1.1.0: minimist "^1.2.5" tslib "^2.0.0" -autoprefixer@9.7.4: - version "9.7.4" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.4.tgz#f8bf3e06707d047f0641d87aee8cfb174b2a5378" - integrity sha512-g0Ya30YrMBAEZk60lp+qfX5YQllG+S5W3GYCFvyHTvhOki0AEQJLPEcIuGRsqVwLi8FvXPVtwTGhfr38hVpm0g== +autoprefixer@10.4.19, autoprefixer@^10.4.19: + version "10.4.19" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.19.tgz#ad25a856e82ee9d7898c59583c1afeb3fa65f89f" + integrity sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew== dependencies: - browserslist "^4.8.3" - caniuse-lite "^1.0.30001020" - chalk "^2.4.2" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^7.0.26" - postcss-value-parser "^4.0.2" - -autoprefixer@^10.4.14: - version "10.4.14" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.14.tgz#e28d49902f8e759dd25b153264e862df2705f79d" - integrity sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ== - dependencies: - browserslist "^4.21.5" - caniuse-lite "^1.0.30001464" - fraction.js "^4.2.0" + browserslist "^4.23.0" + caniuse-lite "^1.0.30001599" + fraction.js "^4.3.7" normalize-range "^0.1.2" picocolors "^1.0.0" postcss-value-parser "^4.2.0" @@ -11132,7 +11119,7 @@ browserslist-to-esbuild@^2.1.1: dependencies: meow "^13.0.0" -browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.21.5, browserslist@^4.22.2, browserslist@^4.23.0, browserslist@^4.8.3: +browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.22.2, browserslist@^4.23.0: version "4.23.0" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== @@ -11589,11 +11576,16 @@ camelcase@^7.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-7.0.1.tgz#f02e50af9fd7782bc8b88a3558c32fd3a388f048" integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== -caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001587: +caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001587: version "1.0.30001621" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001621.tgz#4adcb443c8b9c8303e04498318f987616b8fea2e" integrity sha512-+NLXZiviFFKX0fk8Piwv3PfLPGtRqJeq2TiNoUff/qB5KJgwecJTvCXDpmlyP/eCI/GUEmp/h/y5j0yckiiZrA== +caniuse-lite@^1.0.30001599: + version "1.0.30001636" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz#b15f52d2bdb95fad32c2f53c0b68032b85188a78" + integrity sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg== + capital-case@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" @@ -16735,10 +16727,10 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fraction.js@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" - integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== +fraction.js@^4.3.7: + version "4.3.7" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" + integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== fragment-cache@^0.2.1: version "0.2.1" @@ -25436,7 +25428,7 @@ postcss-value-parser@^3.3.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== -postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: +postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== @@ -25450,7 +25442,7 @@ postcss@^6.0.14, postcss@^6.0.9: source-map "^0.6.1" supports-color "^5.4.0" -postcss@^7.0.11, postcss@^7.0.18, postcss@^7.0.26, postcss@^7.0.32: +postcss@^7.0.11, postcss@^7.0.18, postcss@^7.0.32: version "7.0.39" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==