0.9.8 • Published 5 months ago

cypress-wait-frames v0.9.8

Weekly downloads
-
License
MIT
Repository
github
Last release
5 months ago

npm GitHub Workflow Status npm bundle size dependency-count

Cypress Wait Frames

Cypress command to wait for any CSS/DOM property to be idle after a specified number of frames.

Installation

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

Do I need this?

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.

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:

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

cy.waitFrames({
  subject: cy.window,
  property: 'outerWidth'
})

cy.log('Resized!') // Executed once 'outerWidth' isn't changed for 20 frames (default).

DocumentElement

cy.waitFrames({
  subject: () => cy.get('html'),
  property: 'clientWidth',
  frames: 10
})

cy.log('Resized!') // Executed once 'clientWidth' isn't changed for 10 frames.

HTMLElement / SVGElement

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

PropertyDefaultTypeDescriptionRequired
subjectundefined() => Cypress.Chainable<Cypress.AutWindow \| JQuery<HTMLElement \| SVGElement>>Subject to watch.:white_check_mark:
propertyundefinedstring \| string[]One or more properties to watch.:white_check_mark:
frames20numberNumber of frames to wait.:x:
timeout30 * 1000numberTimeout in milliseconds before the command should fail.:x:

Yields

A Cypress Promise which resolves to an array of objects (one for each property) or throws an error if timeout is reached:

PropertyTypeDescription
subjectAUTWindow | HTMLElementSubject yielded from subject option chainer.
valuePrimitiveProperty value at which the function resolved.
propertystringAwaited property name.
timeDOMHighResTimestampTime in ms that took to resolve since invoking.

Properties

DOM properties

cy.waitFrames({
  subject: () => cy.get('html'),
  property: 'clientWidth'
})

CSS properties

cy.waitFrames({
  subject: () => cy.get('#my-element'),
  property: 'background-color'
})

:bulb: Use kebab-case for CSS properties. 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.

cy.waitFrames({
  subject: cy.window,
  property: 'visualViewport.offsetTop'
})
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:

cy.waitFrames({
  subject: () => cy.get('a').eq(0),
  property: ['background-color', 'scrollTop', 'getBoundingClientRect.top']
})

License

MIT