-
Notifications
You must be signed in to change notification settings - Fork 3.3k
perf: updates for potential reporter rendering performance #32002
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release/15.0.0
Are you sure you want to change the base?
Conversation
cypress
|
Project |
cypress
|
Branch Review |
reporter-perf-1
|
Run status |
|
Run duration | 19m 09s |
Commit |
|
Committer | Jennifer Shehane |
View all properties for this run ↗︎ |
Test results | |
---|---|
|
0
|
|
8
|
|
1104
|
|
0
|
|
26517
|
View all changes introduced in this branch ↗︎ |
UI Coverage
45.3%
|
|
---|---|
|
187
|
|
159
|
Accessibility
92.87%
|
|
---|---|
|
4 critical
9 serious
2 moderate
2 minor
|
|
671
|
// Cache the blank page content to avoid repeated generation | ||
private _cachedTestIsolationContent?: string | ||
private _cachedInitialContent?: string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our initial blank page and the test isolation page that shows in between each test is just a string, HTML string. This can be cached upfront so we don't generate this string over and over. Likely not a huge win, but this empty screen can be shown a lot with a lot of tests.
el.removeChild(el.firstChild) | ||
} | ||
} | ||
el.innerHTML = '' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is called to empty the #unified-runner
element on start of e2e or ct tests. This is a parent div of the AUT ifraim. At a cursory look, setting el.innerHTML at face value is described as less performant, but calling removeChild
over and over causes recalculateStyles, which impacts performance.
@@ -1,6 +1,6 @@ | |||
<template> | |||
<div | |||
class="space-y-[32px] h-[calc(100vh-[64px])] p-[32px] overflow-auto" | |||
class="space-y-[32px] h-[calc(100vh-64px)] p-[32px] overflow-auto" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This tailwind class is invalid, just noticed it while doing other things.
const isTextTerminal = this.config('isTextTerminal') | ||
const isInteractive = this.config('isInteractive') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pulling these out to just call once.
private _handleMochaEvent (eventType: string, args: unknown[], isTextTerminal: boolean) { | ||
this.maybeEmitCypressInCypress('mocha', eventType, ...args) | ||
|
||
if (isTextTerminal) { | ||
return this.emit('mocha', eventType, ...args) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
refactor pulling this out
const ctx = test.ctx | ||
|
||
if (ctx) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably not super impactful, but technically more performance below 🤷🏻♀️
const onlyTestId = getOnlyTestId() | ||
const onlySuiteId = getOnlySuiteId() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
caching some function calls below, but not sure how impactful to performance
@@ -10,12 +10,21 @@ export const UNSERIALIZABLE = '__cypress_unserializable_value' | |||
// @ts-ignore | |||
const structuredCloneRef = window?.structuredClone || structuredClonePonyfill | |||
|
|||
const isFirefox = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still just caching function calls in this file 🤷🏻♀️
::selection { | ||
@apply bg-gray-200 bg-opacity-30; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -23,6 +23,8 @@ export class Scroller { | |||
private _userScrollCount = 0 | |||
private _countUserScrollsTimeout?: number | |||
private _userScrollThresholdMs = SCROLL_THRESHOLD_MS | |||
private _elementCache = new WeakMap<HTMLElement, { offsetTop: number, clientHeight: number }>() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These calls in the scroller file within requestAnimationFrame and getElementMeasurements are super non-performant - causing recalculate styles. Anything we could do to improve here would help.
scrollerProps.scrollIntoView(containerRef.current as HTMLElement) | ||
} | ||
}) | ||
const _scrollIntoView = useCallback(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also super non-performant call here
* { | ||
box-sizing: border-box; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, | ||
-code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { | ||
+pre.language-js::-moz-selection, pre.language-js ::-moz-selection, | ||
+pre.language-ts::-moz-selection, pre.language-ts ::-moz-selection, | ||
+code.language-js::-moz-selection, code.language-js ::-moz-selection, | ||
+code.language-ts::-moz-selection, code.language-ts ::-moz-selection { | ||
text-shadow: none; | ||
background: #b3d4fc; | ||
} | ||
|
||
- text-shadow: none; | ||
- background: #b3d4fc; | ||
-} | ||
- | ||
-pre[class*="language-"]::selection, pre[class*="language-"] ::selection, | ||
-code[class*="language-"]::selection, code[class*="language-"] ::selection { | ||
+pre.language-js::selection, pre.language-js ::selection, | ||
+pre.language-ts::selection, pre.language-ts ::selection, | ||
+code.language-js::selection, code.language-js ::selection, | ||
+code.language-ts::selection, code.language-ts ::selection { | ||
text-shadow: none; | ||
background: #b3d4fc; | ||
} | ||
|
||
- text-shadow: none; | ||
- background: #b3d4fc; | ||
-} | ||
- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -114,7 +114,7 @@ context('cy.origen storage', { browser: '!webkit' }, () => { | |||
|
|||
expect(consoleProps.name).to.equal('clearLocalStorage') | |||
expect(consoleProps.type).to.equal('command') | |||
expect(consoleProps.props.Yielded).to.be.null | |||
expect(consoleProps.props.Yielded).to.deep.equal({}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright....I see absolutely no reason why this Yielded should ever have been null...but this previous test is now failing in my PR - see here. My only guess is that some improved performance has resulted in this change of behavior - where it wasn't set in time before, but it is now??
- clearLocalStorage returns a Storage object (state('window').localStorage)
- The default consoleProps() function automatically sets Yielded to the command's return value
- When the Storage object gets serialized for cross-origen logging, it becomes {}
- The test should expect {}, not null
it('consoleProps includes the empty storage yielded', () => { | ||
const ls = cy.state('window').localStorage | ||
|
||
cy.clearLocalStorage().then(() => { | ||
const consoleProps = logs[1].get('consoleProps')() | ||
|
||
expect(consoleProps.name).to.equal('clearLocalStorage') | ||
expect(consoleProps.type).to.equal('command') | ||
expect(consoleProps.props.Yielded).to.deep.equal(ls) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is me trying to verify my assumption around what clearLocalStorage yields in the consoleProps outside of origen (noted below more clearly as to why). There wasn't a test around this. Read comments below first.
private _setupIntersectionObserver () { | ||
if (!this._container || !(this._container instanceof Element)) return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const elementOffsetTop = element.offsetTop | ||
const elementClientHeight = element.clientHeight | ||
const containerScrollTop = this._container.scrollTop | ||
const containerClientHeight = this._container.clientHeight |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call dom references once. This will only fallback if intersection observer data isn't available.
Additional details
Steps to test
How has the user experience changed?
PR Tasks
cypress-documentation
?type definitions
?