https://github.com/smastrom/cypress-wait-frames
🪂 Cypress command to wait for any CSS/DOM property to be idle after n frames.
https://github.com/smastrom/cypress-wait-frames
cypress cypress-command cypress-css cypress-frames cypress-promise cypress-raf cypress-scroll cypress-wait
Last synced: over 1 year ago
JSON representation
🪂 Cypress command to wait for any CSS/DOM property to be idle after n frames.
- Host: GitHub
- URL: https://github.com/smastrom/cypress-wait-frames
- Owner: smastrom
- License: mit
- Created: 2023-01-20T19:02:33.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2023-12-09T20:36:50.000Z (over 2 years ago)
- Last Synced: 2025-03-24T01:51:39.519Z (over 1 year ago)
- Topics: cypress, cypress-command, cypress-css, cypress-frames, cypress-promise, cypress-raf, cypress-scroll, cypress-wait
- Language: TypeScript
- Homepage:
- Size: 1.03 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
  

# Cypress Wait Frames
Cypress command to wait for any CSS/DOM property to be idle after a specified number of frames.
## Installation
```bash
pnpm add cypress-wait-frames
```
Import the package in your **commands.js**:
```js
import 'cypress-wait-frames'
```
If using TypeScript, optionally install the latest version of [csstype](https://www.npmjs.com/package/csstype) for CSS properties autocompletion:
```bash
pnpm add -D csstype
```
## Do I need this?
Cypress retry ability on [built-in assertions](https://docs.cypress.io/guides/core-concepts/retry-ability#Built-in-assertions) is very powerful and most likely you don't need this package or to use `cy.wait`. For example:
```js
cy.scrollTo(0, 1200)
// No need for cy.wait(t) to make sure scroll is completed
cy.window().eq('scrollY').should('be.approximately', 1200, 2) // Will retry until it passes
```
Documentation on [retry-ability](https://docs.cypress.io/guides/core-concepts/retry-ability) is very detailed and it might already contain the answer you're looking for.
## When I find it useful
There are cases where it's very hard to retain retry-ability and you might find yourself guessing timings using `cy.wait` or increasing the retry-ability timeout.
For example when asserting properties not available within Cypress queries:
```js
cy.get('h1').eq(15).scrollIntoView()
// Need to add cy.wait(t) to make sure scroll is completed
cy.get('h1')
.eq(15)
.then((el) => {
cy.wrap(el[0].getBoundingClientRect().top).should('be.approximately', 0, 2)
})
```
But scenarios can be disparate and more complex. Bottom line is that if you find yourself using `cy.wait()` as last resort to obtain values or to wait for DOM/CSS properties to be idle, this package might be useful.
## Usage
### Window
```js
cy.waitFrames({
subject: cy.window,
property: 'outerWidth'
})
cy.log('Resized!') // Executed once 'outerWidth' isn't changed for 20 frames (default).
```
### DocumentElement
```js
cy.waitFrames({
subject: () => cy.get('html'),
property: 'clientWidth',
frames: 10
})
cy.log('Resized!') // Executed once 'clientWidth' isn't changed for 10 frames.
```
### HTMLElement / SVGElement
```js
cy.waitFrames({
subject: () => cy.get('a').eq(0),
property: 'getBoundingClientRect.top'
}).then(([{ value }]) => {
cy.wrap(value).should('be.approximately', 0, 2) // Asserts that top is 0 after 20 frames (default).
})
```
### Options
| Property | Default | Type | Description | Required |
| ---------- | ---------- | --------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------ |
| `subject` | undefined | `() => Cypress.Chainable>` | Subject to watch. | :white_check_mark: |
| `property` | undefined | `string \| string[]` | One or more properties to watch. | :white_check_mark: |
| `frames` | 20 | `number` | Number of frames to wait. | :x: |
| `timeout` | 30 \* 1000 | `number` | Timeout in milliseconds before the command should fail. | :x: |
## Yields
A [Cypress Promise](https://docs.cypress.io/api/utilities/promise) which resolves to an array of objects (one for each property) or throws an error if `timeout` is reached:
| Property | Type | Description |
| ---------- | ---------------------------- | ----------------------------------------------- |
| `subject` | `AUTWindow` \| `HTMLElement` | Subject yielded from `subject` option chainer. |
| `value` | `Primitive` | Property value at which the function resolved. |
| `property` | `string` | Awaited property name. |
| `time` | `DOMHighResTimestamp` | Time in ms that took to resolve since invoking. |
## Properties
### DOM properties
```js
cy.waitFrames({
subject: () => cy.get('html'),
property: 'clientWidth'
})
```
### CSS properties
```js
cy.waitFrames({
subject: () => cy.get('#my-element'),
property: 'background-color'
})
```
:bulb: Use _kebab-case_ for CSS properties. [getComputedStyle](https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle) is used internally to get the values.
### Nested properties / methods
You can watch for methods or objects **maximum 1 nested property** which returns a primitive.
```js
cy.waitFrames({
subject: cy.window,
property: 'visualViewport.offsetTop'
})
```
```js
cy.waitFrames({
subject: () => cy.get('a').eq(0),
property: 'getBoundingClientRect.top'
})
```
:warning: Methods with arity greater than 0 are not supported, (e.g. `getAttribute('href')`).
### Mixed properties / methods
You can watch for multiple properties as well, `waitFrames` will resolve once all properties are idle:
```js
cy.waitFrames({
subject: () => cy.get('a').eq(0),
property: ['background-color', 'scrollTop', 'getBoundingClientRect.top']
})
```
## License
MIT