Cypress Tip: Don't Overuse the Visibility Assertion
Tags: javascript, testing, cypress
Published: 2021-02-26 18:10:18

[Cypress](https://www.cypress.io/) makes [assertions](https://docs.cypress.io/guides/references/assertions.html) easy with the [`should`](https://docs.cypress.io/api/commands/should.html) command and an intuitive way to leverage the ubiquitous [Chai](https://www.chaijs.com/) assertion library. 

Let's say, for example, that our application is the [Real World App](https://github.com/cypress-io/cypress-realworld-app) and we need to assert that upon navigating to Home the avatar at the top left is visible. We could write the test like this:
```javascript
describe('Home', () => {
  before('sign in and navigate to Home', () => {
	// ...
  })
  it('see avatar', () => {
    cy.get('#avatar')
	  .should('be.visible')
  })
})
``` 

This is 🔥 fine, but on multiple occasions, I've seen an overuse of this visibility assertion. For example, when filling out a form field, you might assert visibility between the query and the action like this:

```javascript
describe('Sign In', () => {
  before('navigate to Sign In', () => {
	// ...
  })
  it('sign in', () => {
    cy.get('#username')
      .should('be.visible')
      .type('iheartjs')
    cy.get('#password')
      .should('be.visible')
      .type('password')
    cy.get('button#sign-in')
      .should('be.visible')
      .click()
    // ...
  })
})
```

It makes sense why we might do this: to avoid interacting with an element before it's visible. However, this is usually unnecessary and could be considered bad practice. 

First, it's unnecessary because of two implicit behaviors of Cypress: [actionability](https://docs.cypress.io/guides/core-concepts/interacting-with-elements.html#Actionability) assertions and command [retry-ability](https://docs.cypress.io/guides/core-concepts/retry-ability.html). Cypress will not attempt to perform certain actions on an element unless it's visible. If it isn't visible, Cypress repeatedly retries this assertion until either the assertion passes and the next command is executed or the timeout is reached and it fails.
Now the test can be written this way:
```javascript
describe('Sign In', () => {
  before('navigate to Sign In', () => {
	// ...
  })
  it('sign in', () => {
    cy.get('#username')
      .type('iheartjs')
    cy.get('#password')
      .type('password')
    cy.get('button#sign-in')
      .click()
    // ...
  })
})
```
Not only is there less code to manage, but now there's less noise in the [Command Log](https://docs.cypress.io/guides/core-concepts/test-runner.html#Command-Log)!

To be clear, we're assuming that the example is not a component test; and while we want to ensure that a user is able to sign in by filling in the fields and clicking a button, we have other tests to ensure form components work as intended. In that vein, it could also be considered bad practice to assert visibility even if it were necessary for a working test. 
The alternative? Assert visibility using the [`:visible`](https://api.jquery.com/visible-selector/) selector (jQuery's extension to native [CSS pseudo-classes](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes)).

When you run the iteration below, Cypress will only perform the action on the element until it's visible.

```javascript
describe('Sign In', () => {
  before('navigate to Sign In', () => {
	// ...
  })
  it('sign in', () => {
    cy.get('#username:visible')
      .type('iheartjs')
    cy.get('#password:visible')
      .type('password')
    cy.get('button#sign-in:visible')
      .click()
    // ...
  })
})
```
While this isn't necessary in cases like this, in the real world, you might run into a situation where you need to make the assertion solely for the purpose of test resiliency or debuggability.

In addition to visibility, there are several other [default assertions](https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html#Default-Assertions) - like ensuring the element is not disabled - that Cypress makes to determine [actionability](https://docs.cypress.io/guides/core-concepts/interacting-with-elements.html#Actionability). Check out the Cypress docs for more in-depth content.