Kathrine Stallings
Kathrine Stallings

Reputation: 163

How to Wait until page is fully loaded

I'm using Cypress to test my spa. Sometimes the page displays quickly and sometimes it is very slow. I need to be able to check for a button or text that will display once the page is loaded, but do not want to wait for eternity.

I've been using excessively long wait periods but would like the test to run faster.

let targeturl = 'http:\\something.com'
let longwait = 2500

describe('Update Case', () => {
  it('Create Case', () => {   
    cy.visit(targeturl)
    cy.wait(longwait)
    cy.get('button').contains('Create').click()

I want to be able to set a wait that waits until the button 'Create' is displayed.

Upvotes: 15

Views: 57580

Answers (4)

Cat Perry
Cat Perry

Reputation: 1062

For any newcomers to this question/problem:

The Cypress docs explicitly discourage arbitrary wait() usage, while thankfully now supplying solutions using intercept() and an aliased route.

Here's how it'd work per the docs. Say you want to wait for the /users page/endpoint to load and then you want to check that a DOM element like a table is present, here's how you'd do it.

cy.intercept('GET', '/users').as('getUsers')
cy.get('[data-testid="fetch-users"]').click()
cy.wait('@getUsers') // <--- wait explicitly for this route to finish
cy.get('table tr').should('have.length', 2)

And if after that you still have issues, like XHR request still completing after page load and therefore halting your element from appearing, then you can pass the timeout prop to cy.get() like this

cy.get('table tr', { timeout: 20000 }).should('have.length', 2)

Cypress wont wait for that whole length of time if it's already loaded and doesnt need it, thanks to your previous intercept/aliased route usage (unlike wait which stalls your tests no matter what.) But that'll give you extra padding if you need it.

Upvotes: 1

mariano_c
mariano_c

Reputation: 431

What about writing some assertion like .should() :

let targeturl = 'http:\\something.com'
let longwait = 2500

describe('Update Case', () => {
  it('Create Case', () => {   
    cy.visit(targeturl)
    cy.url().should('include',targeturl)
    cy.get('button').contains('Create').click()

That worked for me in some cases I needed to have page load complete before selecting any content from page.

Upvotes: 1

DurkoMatko
DurkoMatko

Reputation: 5864

I think you might want to use timeout option of visit:

cy.visit(targeturl, { timeout: 30000 })

I remember I was having similar issue in the past, this Github issue provided me some useful information back then.

Upvotes: -3

Zach Bloomquist
Zach Bloomquist

Reputation: 5881

By default, Cypress will wait for your page to load all resources before continuing the test. Your cy.wait() shouldn't be necessary. The default timeout for cy.visit() is 60 seconds.

Also, cy.get() will retry finding your element until the element exists. The default timeout is 4 seconds, but you can increase it.

Something like this is generally all you need:

describe('Update Case', () => {
  it('Create Case', () => {   
    cy.visit(targeturl)
    cy.get('button').contains('Create').click()

If you find that this isn't working, perhaps because your page takes more than 4 seconds to render after it loads all resources, then you can do something like this:

describe('Update Case', () => {
  it('Create Case', () => {   
    cy.visit(targeturl)
    // wait up to 30 seconds for some element to exist before continuing the test
    cy.get('.some-element-in-your-app-that-only-exists-once-page-has-loaded', { timeout: 30000 })
    cy.get('button').contains('Create').click()

In general, you shouldn't ever need to use cy.wait() to delay your tests by a certain number of milliseconds. Doing so is almost always a bad practice.

Upvotes: 20

Related Questions