-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Experimental fast visibility #6337
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.8.0
Are you sure you want to change the base?
Changes from all commits
deaaaf2
ef24e0c
d4d4ca9
adf79b2
e6f7d37
e2bf2ff
7d81ab4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -26,6 +26,119 @@ inform your testing strategy, and ship high-quality code with confidence. | |||||
|
|
||||||
| ::: | ||||||
|
|
||||||
| ## Visibility | ||||||
|
|
||||||
| ### Default Behavior | ||||||
|
|
||||||
| Cypress checks a lot of things to determine an element's visibility. The | ||||||
| following calculations factor in CSS translations and transforms. | ||||||
|
|
||||||
| #### An element is considered hidden if: | ||||||
|
|
||||||
| - Its `width` or `height` is `0`. | ||||||
| - Its CSS property (or ancestors) is `visibility: hidden`. | ||||||
| - Its CSS property (or ancestors) is `display: none`. | ||||||
| - Its CSS property is `position: fixed` and it's offscreen or covered up. | ||||||
| - Any of its ancestors **hides overflow**\* | ||||||
| - AND that ancestor has a `width` or `height` of `0` | ||||||
| - AND an element between that ancestor and the element is `position: absolute` | ||||||
| - Any of its ancestors **hides overflow**\* | ||||||
| - AND that ancestor or an ancestor between it and that ancestor is its offset | ||||||
| parent | ||||||
| - AND it is positioned outside that ancestor's bounds | ||||||
| - Any of its ancestors **hides overflow**\* | ||||||
| - AND the element is `position: relative` | ||||||
| - AND it is positioned outside that ancestor's bounds | ||||||
|
|
||||||
| \***hides overflow** means it has `overflow: hidden`, `overflow-x: hidden`, | ||||||
| `overflow-y: hidden`, `overflow: scroll`, or `overflow: auto` | ||||||
|
|
||||||
| :::info | ||||||
|
|
||||||
| <strong>Opacity</strong> | ||||||
|
|
||||||
| Elements where the CSS property (or ancestors) is `opacity: 0` are considered | ||||||
| hidden when | ||||||
| [asserting on the element's visibility directly](/app/references/assertions#Visibility). | ||||||
|
|
||||||
| However elements where the CSS property (or ancestors) is `opacity: 0` are | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| considered actionable and any commands used to interact with the hidden element | ||||||
| will perform the action. | ||||||
|
|
||||||
| ::: | ||||||
|
|
||||||
| ### Experimental Fast Visibility | ||||||
|
|
||||||
| You can enable a faster visibility detection algorithm using [`experimentalFastVisibility`](/app/references/experiments#Experimental-Fast-Visibility). | ||||||
|
|
||||||
| This algorithm is more accurate and less resource-intensive than the default behavior, but it has slightly different semantics. | ||||||
|
|
||||||
| When `experimentalFastVisibility` is enabled, an element is considered hidden if: | ||||||
|
|
||||||
| - Its `width` or `height` is `0` | ||||||
| - Its computed CSS properties prevent it from being clicked on or visible: | ||||||
| - `visibility: hidden` | ||||||
| - `opacity: 0` | ||||||
| - `display: none` | ||||||
| - `pointer-events: none` | ||||||
| - It is positioned fully outside of the browser viewport | ||||||
| - _this is a known compatibility issue with the legacy visibility algorithm_ when it comes to asserting visibility. It will be addressed during the course of this experiment. | ||||||
| - It is fully covered or clipped by another element | ||||||
|
|
||||||
| Keep up-to-date with the the progress of this experiment in the [Cypress repository](https://github.com/cypress-io/cypress/issues/33043). | ||||||
|
|
||||||
| #### Limitations | ||||||
|
|
||||||
| Experimental fast visibility is an experimental feature that is still under development. It is not yet fully compatible with the legacy visibility algorithm. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does this imply that we are trying to achieve backwards compatibility at some point? |
||||||
|
|
||||||
| - Shadow DOM is not yet supported. Tests that interact with Shadow DOM elements may fail or behave incorrectly. | ||||||
| - Elements outside of the browser's viewport are not yet correctly identified as visible. Scroll elements into view before testing. | ||||||
|
|
||||||
| #### Common Compatibility Issues | ||||||
|
|
||||||
| When enabling fast visibility, you may encounter differences in how elements are detected. The fast algorithm provides more geometrically accurate visibility detection, which may reveal that elements previously considered visible are actually hidden. | ||||||
|
|
||||||
| **Elements Outside Viewport** | ||||||
|
|
||||||
| Elements positioned outside the viewport are now correctly identified as hidden. Scroll elements into view before testing: | ||||||
|
|
||||||
| ```javascript | ||||||
| // Before | ||||||
| cy.get('.off-screen-element').should('be.visible') | ||||||
|
|
||||||
| // After | ||||||
| cy.get('.off-screen-element').scrollIntoView().should('be.visible') | ||||||
| ``` | ||||||
|
|
||||||
| **Covered Elements** | ||||||
|
|
||||||
| Elements covered by other elements are now correctly identified as hidden. Test the covering element or the user interaction that reveals the covered element: | ||||||
|
|
||||||
| ```javascript | ||||||
| // Test the user action that reveals the element | ||||||
| cy.get('.toggle-button').click() | ||||||
| cy.get('.covered-element').should('be.visible') | ||||||
| ``` | ||||||
|
|
||||||
| **Zero-Dimension Containers** | ||||||
|
|
||||||
| Containers with zero dimensions are now correctly identified as hidden. Test the child element instead of the container: | ||||||
|
|
||||||
| ```javascript | ||||||
| // Test the child element that should be visible | ||||||
| cy.get('.zero-dimension-container .child-element').should('be.visible') | ||||||
| ``` | ||||||
|
|
||||||
| **Elements with `pointer-events: none`** | ||||||
|
|
||||||
| Elements with `pointer-events: none` may be detected as hidden when they are visible. Do not assert visibility on elements with `pointer-events: none`, as they cannot be interacted with. | ||||||
|
|
||||||
| :::caution | ||||||
|
|
||||||
| **Important:** If tests fail after enabling fast visibility, the fast algorithm is likely correct and tests should be updated to match the actual behavior. | ||||||
|
|
||||||
| ::: | ||||||
|
|
||||||
| ## Actionability | ||||||
|
|
||||||
| Some commands in Cypress are for interacting with the DOM such as: | ||||||
|
|
@@ -71,45 +184,6 @@ Whenever Cypress cannot interact with an element, it could fail at any of the | |||||
| above steps. You will usually get an error explaining why the element was not | ||||||
| found to be actionable. | ||||||
|
|
||||||
| ### Visibility | ||||||
|
|
||||||
| Cypress checks a lot of things to determine an element's visibility. The | ||||||
| following calculations factor in CSS translations and transforms. | ||||||
|
|
||||||
| #### An element is considered hidden if: | ||||||
|
|
||||||
| - Its `width` or `height` is `0`. | ||||||
| - Its CSS property (or ancestors) is `visibility: hidden`. | ||||||
| - Its CSS property (or ancestors) is `display: none`. | ||||||
| - Its CSS property is `position: fixed` and it's offscreen or covered up. | ||||||
| - Any of its ancestors **hides overflow**\* | ||||||
| - AND that ancestor has a `width` or `height` of `0` | ||||||
| - AND an element between that ancestor and the element is `position: absolute` | ||||||
| - Any of its ancestors **hides overflow**\* | ||||||
| - AND that ancestor or an ancestor between it and that ancestor is its offset | ||||||
| parent | ||||||
| - AND it is positioned outside that ancestor's bounds | ||||||
| - Any of its ancestors **hides overflow**\* | ||||||
| - AND the element is `position: relative` | ||||||
| - AND it is positioned outside that ancestor's bounds | ||||||
|
|
||||||
| \***hides overflow** means it has `overflow: hidden`, `overflow-x: hidden`, | ||||||
| `overflow-y: hidden`, `overflow: scroll`, or `overflow: auto` | ||||||
|
|
||||||
| :::info | ||||||
|
|
||||||
| <strong>Opacity</strong> | ||||||
|
|
||||||
| Elements where the CSS property (or ancestors) is `opacity: 0` are considered | ||||||
| hidden when | ||||||
| [asserting on the element's visibility directly](/app/references/assertions#Visibility). | ||||||
|
|
||||||
| However elements where the CSS property (or ancestors) is `opacity: 0` are | ||||||
| considered actionable and any commands used to interact with the hidden element | ||||||
| will perform the action. | ||||||
|
|
||||||
| ::: | ||||||
|
|
||||||
| ### Disability | ||||||
|
|
||||||
| Cypress checks whether the `disabled` property is `true` on a | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -38,6 +38,7 @@ configuration to Cypress. | |||||
| | `experimentalModifyObstructiveThirdPartyCode` | `false` | Whether Cypress will search for and replace obstructive code in third party `.js` or `.html` files. NOTE: Setting this flag removes [Subresource Integrity (SRI)](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity). | | ||||||
| | `experimentalSourceRewriting` | `false` | Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement algorithm. See [#5273](https://github.com/cypress-io/cypress/issues/5273) for details. | | ||||||
| | `experimentalWebKitSupport` | `false` | Enable experimental support for running tests in WebKit. When set, installs of `playwright-webkit` will be detected and available in Cypress. See [Launching Browsers](/app/references/launching-browsers#WebKit-Experimental) for more information. | | ||||||
| | `experimentalFastVisibility` | `false` | Enables a faster visibility detection algorithm using point sampling. This can significantly improve performance when interacting with complex DOM structures. See [Experimental Fast Visibility](/app/references/experiments#Experimental-Fast-Visibility) for more details. | | ||||||
| | `retries.experimentalStrategy` | N/A | Applies a strategy for test retries according to your "flake tolerance"; options are detect-flake-but-always-fail or detect-flake-and-pass-on-threshold. See [Experimental Retries](/app/references/experiments#Experimental-Flake-Detection-Features) for more details. | | ||||||
| | `retries.experimentalOptions` | N/A | Sets retries strategy-specific options like maxRetries, passesRequired, and stopIfAnyPassed. See [Experimental Retries](/app/references/experiments#Experimental-Flake-Detection-Features) for more details. | | ||||||
|
|
||||||
|
|
@@ -124,6 +125,91 @@ modified HTML or JS value. | |||||
|
|
||||||
| ::: | ||||||
|
|
||||||
| ## Experimental Fast Visibility | ||||||
|
|
||||||
| The `experimentalFastVisibility` option enables a faster visibility detection algorithm that uses point sampling instead of the legacy algorithm. This can significantly improve performance when interacting with complex DOM structures. | ||||||
|
|
||||||
| ### Benefits | ||||||
|
|
||||||
| The fast visibility algorithm provides several advantages over the legacy algorithm: | ||||||
|
|
||||||
| - **Better performance**: Constant-time in the best case, and bounded exponential in the worst case (when point sampling on a fully hidden element) | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we know how this compares directly to the current algorithm or is determining complexity for that incredibly challenging to distill briefly? |
||||||
| - **Memory efficiency**: Reduces memory usage and prevents browser crashes during visibility checks | ||||||
| - **Reduced layout thrashing**: Avoids repeated access of CSS properties that require layout recalculation | ||||||
| - **Better coverage detection**: Can detect when an element is fully covered by positioned elements outside its ancestor tree | ||||||
|
|
||||||
| ### How It Works | ||||||
|
|
||||||
| The fast visibility algorithm: | ||||||
|
|
||||||
| 1. Assumes `body` and `html` are always visible (consistent with current visibility behavior) | ||||||
| 2. Uses the built-in `checkVisibility` method as a first pass, with all options enabled | ||||||
| 3. For `<option>` or `<optgroup>` elements, defers to the visibility of the parent `<select>` element | ||||||
| 4. If the element is still considered visible, performs a more comprehensive check with an adaptive point sampling algorithm | ||||||
|
|
||||||
| The point sampling algorithm: | ||||||
|
|
||||||
| - Checks the four corners and center of the element's bounding rectangle | ||||||
| - If none of these points are visible, subdivides the bounding rectangle into four sub-rectangles and performs the same sampling recursively | ||||||
| - Returns `true` if any part of the element is visible | ||||||
| - Stops subdividing when rectangles fall below 1px in both dimensions or reach a maximum depth | ||||||
|
|
||||||
| ### Configuration | ||||||
|
|
||||||
| Enable fast visibility by setting `experimentalFastVisibility` to `true` in your Cypress configuration: | ||||||
|
|
||||||
| :::cypress-config-example | ||||||
|
|
||||||
| ```js | ||||||
| { | ||||||
| experimentalFastVisibility: true | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| `experimentalFastVisibility` can also be enabled or disabled on a per-test or per-suite basis by passing the `experimentalFastVisibility` option to the test or suite function: | ||||||
|
|
||||||
| :::cypress-config-example | ||||||
|
|
||||||
| ```js | ||||||
| // Enable fast visibility for the entire suite | ||||||
| describe('My Test Suite', { experimentalFastVisibility: true }, () => { | ||||||
| // Disable fast visibility for this test | ||||||
| it( | ||||||
| 'Requires legacy visibility to pass', | ||||||
| { experimentalFastVisibility: false }, | ||||||
| () => { | ||||||
| // ... | ||||||
| } | ||||||
| ) | ||||||
| }) | ||||||
| ``` | ||||||
|
|
||||||
| ::: | ||||||
|
|
||||||
| ### When to Use | ||||||
|
|
||||||
| Consider enabling `experimentalFastVisibility` if you: | ||||||
|
|
||||||
| - Experience performance issues or browser crashes during visibility checks | ||||||
| - Have complex DOM structures with many nested elements | ||||||
| - Need faster test execution times | ||||||
|
|
||||||
| :::caution | ||||||
|
|
||||||
| The experimental fast visibility algorithm is not yet fully compatible with the legacy visibility algorithm. Tests that rely on edge-case behavior of the legacy visibility algorithm may fail or behave incorrectly. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This transition feels awkward but I don't love my suggestion.
Suggested change
|
||||||
|
|
||||||
| - Scroll elements into view before asserting on their visibility. | ||||||
| - Shadow DOM is not yet supported. Tests that interact with Shadow DOM elements may fail or behave incorrectly. | ||||||
| - Elements outside of the browser's viewport are not yet correctly identified as visible. Scroll elements into view before testing. | ||||||
|
|
||||||
| ::: | ||||||
|
|
||||||
| :::info | ||||||
|
|
||||||
| For detailed information about how the fast visibility algorithm works, its differences from the legacy algorithm, and solutions to common compatibility issues, see the [Experimental Fast Visibility](/app/core-concepts/interacting-with-elements#Experimental-Fast-Visibility) section in the [Interacting with Elements](/app/core-concepts/interacting-with-elements) guide. | ||||||
|
|
||||||
| ::: | ||||||
|
|
||||||
| ## Experimental Flake Detection Features | ||||||
|
|
||||||
| ### Experimental Test Retries | ||||||
|
|
@@ -281,6 +367,7 @@ configuration object: | |||||
|
|
||||||
| | Version | Changes | | ||||||
| | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | ||||||
| | [15.8.0](/app/references/changelog#15-8-0) | Added support for `experimentalFastVisibility` experiment. | | ||||||
| | [15.4.0](/app/references/changelog) | Removed `experimentalStudio`. Cypress Studio is available as default behavior. | | ||||||
| | [14.0.0](/app/references/changelog#14-0-0) | Removed `experimentalJustInTimeCompile` and `experimentalSkipDomainInjection` and made it default behavior. | | ||||||
| | [13.14.0](/app/references/changelog#13-14-0) | Added support for configuring the Experimental Just-In-Time (JIT) Compiling for component testing via `experimentalJustInTimeCompile`. | | ||||||
|
|
||||||
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.
More of a nit but this reads kind of strange to me since elements can have multiple properties? Feel free to ignore this since you are just moving the section 😅