Cypress command to wait for any CSS/DOM property to be idle after a specified number of frames.
pnpm add cypress-wait-frames
Import the package in your commands.js:
import 'cypress-wait-frames'
If using TypeScript, optionally install the latest version of csstype for CSS properties autocompletion:
pnpm add -D csstype
Cypress retry ability on built-in assertions is very powerful and most likely you don't need this package or to use cy.wait
. For example:
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 is very detailed and it might already contain the answer you're looking for.
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:
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.
cy.waitFrames({
subject: cy.window,
property: 'outerWidth'
})
cy.log('Resized!') // Executed once 'outerWidth' isn't changed for 20 frames (default).
cy.waitFrames({
subject: () => cy.get('html'),
property: 'clientWidth',
frames: 10
})
cy.log('Resized!') // Executed once 'clientWidth' isn't changed for 10 frames.
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).
})
Property | Default | Type | Description | Required |
---|---|---|---|---|
subject |
undefined | () => Cypress.Chainable<Cypress.AutWindow | JQuery<HTMLElement | SVGElement>> |
Subject to watch. | ✅ |
property |
undefined | string | string[] |
One or more properties to watch. | ✅ |
frames |
20 | number |
Number of frames to wait. | ❌ |
timeout |
30 * 1000 | number |
Timeout in milliseconds before the command should fail. | ❌ |
A Cypress 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. |
cy.waitFrames({
subject: () => cy.get('html'),
property: 'clientWidth'
})
cy.waitFrames({
subject: () => cy.get('#my-element'),
property: 'background-color'
})
💡 Use kebab-case for CSS properties. getComputedStyle is used internally to get the values.
You can watch for methods or objects maximum 1 nested property which returns a primitive.
cy.waitFrames({
subject: cy.window,
property: 'visualViewport.offsetTop'
})
cy.waitFrames({
subject: () => cy.get('a').eq(0),
property: 'getBoundingClientRect.top'
})
getAttribute('href')
).
You can watch for multiple properties as well, waitFrames
will resolve once all properties are idle:
cy.waitFrames({
subject: () => cy.get('a').eq(0),
property: ['background-color', 'scrollTop', 'getBoundingClientRect.top']
})
MIT