w3resource

Interacting with Elements


In this tutorial we will see how Cypress calculates visibility, how it ensures that elements are actionable, how it deals with the animation of elements and finally how you can bypass these checks and force events.

Actionability

Some of the Cypress Commands that you can use to interact with the DOM are as follows:

  • .click()
  • .dblclick()
  • .rightclick()
  • .type()
  • .clear()
  • .check()
  • .uncheck()
  • .select()
  • .trigger()

This commands will stimulate a user’s interaction with your application. Behind the scenes, Cypress will fire the events that a browser will fire thus causing your application’s event binding to fire.

Before Cypress issues any command, it will check the current state of the DOM and take some actions to ensure the DOM element is ready to receive the action.

Cypress waits for the element to pass all of these checks for the duration of the defaultCOmmandTimeout.

Checks and Action Performed

  • Scroll the element into view.
  • Ensure the element is not hidden.
  • Ensure the element is not disabled.
  • Ensure the element is not detached.
  • Ensure the element is not readonly.
  • Ensure the element is not animating.
  • Ensure the element is not covered.
  • Scroll the page if still covered by an element with fixed position.
  • Fire the event at the desired coordinates.

In the situation where Cypress cannot interact with an element, it could fail at any of the steps stated above. You will get an error message that explains why the element was not found to be actionable.

Visibility

Cypress will check a lot of things in order to determine the visibility of an element.

The calculations will factor in CSS translation and transforms.

An element will be considered hidden if:

The width or height is 0

The CSS property (or ancestors) is visibility: hidden

The CSS property (or ancestors) is display: none

The CSS property is position: fixed and it is offscreen or covered up.

Additionally, an element is considered hidden if:

  • Any of the ancestors hides overflow*
    • AND the ancestor has a width or a height of 0
    • AND an element that is between that ancestor and the element has a position: absolute
  • Any of the ancestors hides overflow*
    • AND that ancestor has a height or width of 0
    • AND an element between that ancestor and the element is position: absolute
  • Any of its ancestors hides overflow*
    • AND the element is position: relative
    • AND it is positioned outside the bound of the ancestor

*when we say hides overflow, we mean any of the following: overflow: hidden, overflow-x: hidden, overflow-y : hidden, overflow: scroll, or overflow: auto

Disability

Cypress will check if the disabled property of an element is set to true.

Detached

Every application that re-renders the DOM will actually remove the DOM element and then insert a new DOM element in its place with the newly change attributes.

Cypress will check to see if an element that you are making assertions is detached from the DOM. This will check to see if the element is still within the document of the application under test.

Readonly

Cypress will also check to see if the readonly property of an element is set during .type().

Animations

Cypress automatically determines if an element is animating and then waists until it stops.

In order to calculate whether an element is animating, Cypress will take a sample of the last positons it was at and then calculate the slope of the element.

If the distance exceeds the animationDistanceThreshhold, then Cypress will consider the element to be animating.

You can turn off the checks for animations with the configuration option waitForAnimations.

Covering

It is also important that the element that you are attempting to interact with is not covered by a parent element.

For instance, an element can pass all the previous checks, but a giant dialog will be covering the entire screen thus making the interaction with the element impossible.

Scrolling

Before Cypress interacts with an element it will always scroll it into view. The scrolling logic is only applicable to commands that are actionable.

Once Cypress scrolls the element, if cypress determines that it is still being covered up, Cypress will continue to scroll and nudge the page until the element becomes visible. This scenario is common when you have a position: fixed or a position: sticky navigation element that is fixed at the top of the page.

Coordinates

Once it is verified that the element is actionable, Cypress will fire all the appropriate events and the corresponding default actions. Here is an example of how to get the coordinate of a button:

'''describe('The Home Page', () => {
  it('successfully loads', () => {
    cy.visit(`http://localhost:3000`)
      cy.get('button').click({ position: 'topLeft', multiple:true, force:true})
  })
})'''
cypress: interacting with elements image

Debugging

It can be difficult to debug problems when Cypress does not consider the elements actionable. Even though you should see a nice error message, there is nothing like visually inspecting and poking at the DOM yourself to know the reason why.

To debug effectively, it is recommended that you pace a debugger or using the .debug() command directly BEFORE the action.

You can also bind to events that Cypress will fire while it is working with your element.

Forcing

Although, the checks above are super helpful at finding situations that would prevent your users from interacting with elements.

There are not sometimes when it is not worth trying to act like a user to get a robot to do the exact steps a user would to interact with an element.

You can pass {force: true} to most action, this option will skip checks, it gives you a hatch to bypasss all of the checks that Cypress normally will go through and then force events to happen.

'''cy.get('button').click({ position: 'topLeft', force:true})'''