From 5dbebe6e5e7fca3af9716bfa8b80830b87641cf4 Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Fri, 3 Nov 2023 14:39:56 -0500 Subject: [PATCH] fix: ensure that chromium based browsers do not send out a lot of font requests when global styles change (#28217) --- cli/CHANGELOG.md | 3 +- .../cypress/e2e/commands/actions/click.cy.js | 4 - .../driver/cypress/e2e/dom/visibility.cy.ts | 25 +---- packages/driver/src/cy/actionability.ts | 44 ++------ .../src/dom/elements/complexElements.ts | 6 - .../driver/src/dom/elements/nativeProps.ts | 5 - packages/server/lib/browsers/chrome.ts | 3 + packages/server/lib/cypress.js | 9 +- packages/server/lib/util/electron-app.js | 13 +++ system-tests/__snapshots__/protocol_spec.js | 44 -------- .../protocolStubFontFlooding.ts | 103 ++++++++++++++++++ .../protocol-stubs/protocolStubResponse.ts | 2 + .../protocol/cypress/e2e/font-flooding.cy.js | 11 ++ .../cypress/fixtures/font-flooding.css | 63 +++++++++++ .../cypress/fixtures/font-flooding.html | 18 +++ system-tests/test/font_flooding_spec.js | 51 +++++++++ system-tests/test/protocol_spec.js | 1 + 17 files changed, 286 insertions(+), 119 deletions(-) create mode 100644 system-tests/lib/protocol-stubs/protocolStubFontFlooding.ts create mode 100644 system-tests/projects/protocol/cypress/e2e/font-flooding.cy.js create mode 100644 system-tests/projects/protocol/cypress/fixtures/font-flooding.css create mode 100644 system-tests/projects/protocol/cypress/fixtures/font-flooding.html create mode 100644 system-tests/test/font_flooding_spec.js diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 13c9059ea30b..db56f06d106b 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -6,7 +6,8 @@ _Released 11/7/2023 (PENDING)_ **Bugfixes:** - Fixed an issue determining visibility when an element is hidden by an ancestor with a shared edge. Fixes [#27514](https://github.com/cypress-io/cypress/issues/27514). -- Fixed an issue with 'other' targets (e.g. pdf documents embedded in an object tag) not fully loading. Fixes [#28228](https://github.com/cypress-io/cypress/issues/28228) +- Fixed an issue where in chromium based browsers, global style updates can trigger flooding of font face requests in DevTools and Test Replay. This can affect performance due to the flooding of messages in CDP. Fixes [#28150](https://github.com/cypress-io/cypress/issues/28150) and [#28215](https://github.com/cypress-io/cypress/issues/28215). +- Fixed an issue with 'other' targets (e.g. pdf documents embedded in an object tag) not fully loading. Fixes [#28228](https://github.com/cypress-io/cypress/issues/28228) and [#28162](https://github.com/cypress-io/cypress/issues/28162). - Fixed an issue where network requests made from tabs/windows other than the main Cypress tab would be delayed. Fixes [#28113](https://github.com/cypress-io/cypress/issues/28113). - Stopped processing CDP events at the end of a spec when Test Isolation is off and Test Replay is enabled. Addressed in [#28213](https://github.com/cypress-io/cypress/pull/28213). diff --git a/packages/driver/cypress/e2e/commands/actions/click.cy.js b/packages/driver/cypress/e2e/commands/actions/click.cy.js index de682862ce0e..97fe26a7b6a0 100644 --- a/packages/driver/cypress/e2e/commands/actions/click.cy.js +++ b/packages/driver/cypress/e2e/commands/actions/click.cy.js @@ -1678,16 +1678,12 @@ describe('src/cy/commands/actions/click', () => { it('can scroll to and click elements in html with scroll-behavior: smooth', () => { cy.get('html').invoke('css', 'scrollBehavior', 'smooth') cy.get('#table tr:first').click() - // Validate that the scrollBehavior is still smooth even after the actionability fixes we do - cy.get('html').invoke('css', 'scrollBehavior').then((scrollBehavior) => expect(scrollBehavior).to.eq('smooth')) }) // https://github.com/cypress-io/cypress/issues/3200 it('can scroll to and click elements in ancestor element with scroll-behavior: smooth', () => { cy.get('#dom').invoke('css', 'scrollBehavior', 'smooth') cy.get('#table tr:first').click() - // Validate that the scrollBehavior is still smooth even after the actionability fixes we do - cy.get('#dom').invoke('css', 'scrollBehavior').then((scrollBehavior) => expect(scrollBehavior).to.eq('smooth')) }) }) }) diff --git a/packages/driver/cypress/e2e/dom/visibility.cy.ts b/packages/driver/cypress/e2e/dom/visibility.cy.ts index 5dc7495afc30..eed827b883b1 100644 --- a/packages/driver/cypress/e2e/dom/visibility.cy.ts +++ b/packages/driver/cypress/e2e/dom/visibility.cy.ts @@ -53,7 +53,7 @@ describe('src/cypress/dom/visibility', () => { expect(fn()).to.be.true }) - it('returns false if window and body < window height', () => { + it('returns false window and body > window height', () => { cy.$$('body').html('
foo
') const win = cy.state('window') @@ -65,29 +65,6 @@ describe('src/cypress/dom/visibility', () => { expect(fn()).to.be.false }) - it('returns true if document element and body > window height', function () { - this.add('
') - const documentElement = Cypress.dom.wrap(cy.state('document').documentElement) - - const fn = () => { - return dom.isScrollable(documentElement) - } - - expect(fn()).to.be.true - }) - - it('returns false if document element and body < window height', () => { - cy.$$('body').html('
foo
') - - const documentElement = Cypress.dom.wrap(cy.state('document').documentElement) - - const fn = () => { - return dom.isScrollable(documentElement) - } - - expect(fn()).to.be.false - }) - it('returns false el is not scrollable', function () { const noScroll = this.add(`\
diff --git a/packages/driver/src/cy/actionability.ts b/packages/driver/src/cy/actionability.ts index d40ffb29ddb7..8cdea1e51cbe 100644 --- a/packages/driver/src/cy/actionability.ts +++ b/packages/driver/src/cy/actionability.ts @@ -8,7 +8,6 @@ import $utils from './../cypress/utils' import type { ElWindowPostion, ElViewportPostion, ElementPositioning } from '../dom/coordinates' import $elements from '../dom/elements' import $errUtils from '../cypress/error_utils' -import { callNativeMethod, getNativeProp } from '../dom/elements/nativeProps' const debug = debugFn('cypress:driver:actionability') const delay = 50 @@ -461,46 +460,24 @@ const verify = function (cy, $el, config, options, callbacks: VerifyCallbacks) { // make scrolling occur instantly. we do this by adding a style tag // and then removing it after we finish scrolling // https://github.com/cypress-io/cypress/issues/3200 - const addScrollBehaviorFix = (element: JQuery) => { - const affectedParents: Map = new Map() + const addScrollBehaviorFix = () => { + let style try { - let parent: JQuery | null = element + const doc = $el.get(0).ownerDocument - do { - if ($dom.isScrollable(parent)) { - const parentElement = parent[0] - const style = getNativeProp(parentElement, 'style') - const styles = getComputedStyle(parentElement) - - if (styles.scrollBehavior === 'smooth') { - affectedParents.set(parentElement, callNativeMethod(style, 'getStyleProperty', 'scroll-behavior')) - callNativeMethod(style, 'setStyleProperty', 'scroll-behavior', 'auto') - } - } - - parent = $dom.getFirstScrollableParent(parent) - } while (parent) + style = doc.createElement('style') + style.innerHTML = '* { scroll-behavior: inherit !important; }' + // there's guaranteed to be a + + diff --git a/system-tests/test/font_flooding_spec.js b/system-tests/test/font_flooding_spec.js new file mode 100644 index 000000000000..7fe55848d08e --- /dev/null +++ b/system-tests/test/font_flooding_spec.js @@ -0,0 +1,51 @@ +const fs = require('fs-extra') +const path = require('path') +const systemTests = require('../lib/system-tests').default +const Fixtures = require('../lib/fixtures') +const { + createRoutes, + setupStubbedServer, + enableCaptureProtocol, +} = require('../lib/serverStub') +const { PROTOCOL_STUB_FONT_FLOODING } = require('../lib/protocol-stubs/protocolStubResponse') + +const getFilePath = (filename) => { + return path.join( + Fixtures.projectPath('protocol'), + 'cypress', + 'system-tests-protocol-dbs', + `${filename}.json`, + ) +} + +const BROWSERS = ['chrome', 'electron'] + +describe('capture-protocol', () => { + setupStubbedServer(createRoutes()) + enableCaptureProtocol(PROTOCOL_STUB_FONT_FLOODING) + + describe('font flooding', () => { + BROWSERS.forEach((browser) => { + it(`verifies the number of font requests is correct - ${browser}`, function () { + return systemTests.exec(this, { + key: 'f858a2bc-b469-4e48-be67-0876339ee7e1', + project: 'protocol', + spec: 'font-flooding.cy.js', + record: true, + expectedExitCode: 0, + port: 2121, + browser, + config: { + hosts: { + '*foobar.com': '127.0.0.1', + }, + }, + }).then(() => { + const protocolEvents = fs.readFileSync(getFilePath('e9e81b5e-cc58-4026-b2ff-8ae3161435a6.db'), 'utf8') + + expect(JSON.parse(protocolEvents).numberOfFontRequests).to.equal(2) + }) + }) + }) + }) +}) diff --git a/system-tests/test/protocol_spec.js b/system-tests/test/protocol_spec.js index 8ac73046544a..7f868174cdd6 100644 --- a/system-tests/test/protocol_spec.js +++ b/system-tests/test/protocol_spec.js @@ -43,6 +43,7 @@ describe('capture-protocol', () => { record: true, expectedExitCode: 0, port: 2121, + spec: 'protocol.cy.js,test-isolation.cy.js', config: { hosts: { '*foobar.com': '127.0.0.1',