How To Test Element Visibility Using Cypress ViewPort

Have you deployed an update to an existing web application only to discover that a particular element is no longer visible due to your new changes?

Within this brief tutorial, you will learn about the Viewport command from Cypress, and see how it can be used together with the get command when asserting the visibility of a DOM element in your test cases.

Prerequisites

To keep this tutorial brief, the following assumptions have been made;

  • You are familiar with using cypress for End-to-End ( E2E ) tests.
  • You have a local installation of the Git CLI.
  • You have a local installation of Node.js .

What is the ViewPort command?

The ViewPort command from cypress is used within a test case to change the default viewport and orientation of the application. When used together with the get command, you can change the viewport of the application being tested several times and assert that a DOM element is being displayed across each viewport. By doing this, you will prevent edge cases where a DOM element is unintentionally hidden in a different viewport.

Let’s proceed to use the ViewPort command within the test suites in a sample Vue.js application. Within the test cases, you will use the Viewport command to change the application’s viewport seven times while asserting that the application’s brand name is shown across the seven viewports.

Cloning Sample Application

Execute the git command below to clone the prebuilt application from the GitHub repository;

git clone github.com/vickywane/https://github.com/vic..

Next, execute the command below to install the dependencies for the application listed in the package.json file.

npm install

With the package installed, you can further execute the command below to run the application before we proceed with testing the existing component;

npm run serve

Writing A Test Suite

The Vue.js application has a single page, and you can create a test suite with test cases to test all that is rendered in the page.

Using your preferred code editor, replace the content of the cypress/integration/Home.spec.js file with the code block below;

// <reference types="cypress" />

context('Default Index Page', () => {
  before(() => {
    cy.visit('/')
  })

  it('Should a header in the home page', () => {
    cy.get('h2').should('exist')
  })

  it('Should contain three images', () => {
    cy.get('img').should(element => {
      expect(element).to.have.length(3)
    }) 
  })

  it('Should contain a description text', () => {
    cy.get('[data-cy=description]').should('exist')
  })
})

The Default Index Page test suite above contains three test cases to assert that the default page contains a header, has three images, and also has a description.

Execute the yarn test command to run the test suite in a headless mode.

Running cypress tests to assert page elements

Using The Viewport Command

By default, cypress will run the test suite at full resolution. However, this will not cover scenarios where an element has been hidden due to a user's varying viewport or a wrongly placed media query.

To handle this scenario, you will make use of the Cypress Viewport command to change the test runner's orientation, then assert that the elements are visible.

Add the content of the code block below into the cypress/integration/Home.spec.js file to add a test case that checks for element visibility across the following device presets

  • iPhone-6
  • Samsung-s10
  • iPhone-X
  • iPhone-XR
  • Samsung-note9
  it('Elements are visible on mobile devices', () => {
    // iphone 6
    cy.viewport('iphone-6')

    cy.get('[data-cy=description]').should('exist')
    cy.get('img').should(element => {
      expect(element).to.have.length(3)
    })

    // iphone x
    cy.viewport('iphone-x')

    cy.get('[data-cy=description]').should('exist')
    cy.get('img').should(element => {
      expect(element).to.have.length(3)
    })

    // iphone xr
    cy.viewport('iphone-xr')

    cy.get('[data-cy=description]').should('exist')
    cy.get('img').should(element => {
      expect(element).to.have.length(3)
    })

    // iphone xr
    cy.viewport('iphone-xr')

    cy.get('[data-cy=description]').should('exist')
    cy.get('img').should(element => {
      expect(element).to.have.length(3)
    })

    // samsung-s10
    cy.viewport('samsung-s10')

    cy.get('[data-cy=description]').should('exist')
    cy.get('img').should(element => {
      expect(element).to.have.length(3)
    })

    // samsung-note9
    cy.viewport('samsung-note9')

    cy.get('[data-cy=description]').should('exist')
    cy.get('img').should(element => {
      expect(element).to.have.length(3)
    })
  })

Note: The device presets below provide predefined resolutions to the Viewport command. You can also specify your resolution by passing in the width and height to the Viewport command.

Although repetitive, the test case above asserts that the description and image elements are visible across the previously listed device viewport.

To see the viewport being changed, you can run the tests using the cypress test runner with the npx command below;

Note: You do not need to install npx, as it ships by default with all recent Node.js installations.

npx cypress open

From the cypress test runner GUI, click the Home.spec.js test to launch your default web browser in an automated mode for running the test.

The image below shows the cypress runner GUI running the test across varying viewports. You can see the different viewports being highlighted in the purple boxes.

Running the cypress across varying mobile viewports

Let's refactor the test case above to fix the repetition by creating a reusable function for changing the viewport and asserting that the two elements are visible. The function will accept the cypress instance and the desired viewport as parameters.

Add the function below into the cypress/integration/Home.spec.js file, right above the context function that contains the cypress test cases.

const assertElementsVisibility = (cy, viewport) => {
  cy.viewport(viewport)

  cy.get('[data-cy=description]').should('exist')
  cy.get('img').should(element => {
    expect(element).to.have.length(3)
  })
}

// context below ...

Next, replace the entire code in the "Elements are visible on mobile devices" section of the cypress/integration/Home.spec.js file with the code below to use the assertElementsVisibility function above.

  it('Elements are visible on mobile devices', () => {
    assertElementsVisibility(cy, 'iphone-6')
    assertElementsVisibility(cy, 'iphone-x')
    assertElementsVisibility(cy, 'iphone-xr')
    assertElementsVisibility(cy, 'iphone-s10')
    assertElementsVisibility(cy, 'iphone-note9')
  })

Now, the test case looks much smaller and much more readable.

Based on your needs, you can also "flip the switch" and assert that an element is not visible on a defined viewport. A practical example of this would be when working with media queries. If you have a media query that hides an element when the viewport becomes smaller, you can also use the viewport command in a cypress test case to assert that the element is not visible across your desired viewport.

Conclusion

In this brief tutorial, you have learned about the Viewport command and the benefits it provides when asserting the responsiveness of your web application.

Enjoyed the article? At Hera, we write technical content like this for developers, programmers, software engineers, developer advocates and CTOs. Wherever you are with content marketing, we'll meet you there and collaborate to meet your goals.

Schedule a meeting, let's work together to attract, educate, and engage your audience.