Cypress reload page until element visible

Viewed 4212

I have following case:

After user uploads a file, there is a table report in the screen. The problem is: the table does not come up automatically, user needs to reload the page and if the file was already processed, the table is shown in screen, if it is still processing, user needs to wait a little bit and reload again.

How do I accomplish this task without using cy.wait() to wait an arbitrary time. I thought something like:

    cy.reload().should(() => {
        expect(document.querySelectorAll('table')).to.not.be.empty
    })

but didn't work

2 Answers

If a should() assertion fails, Cypress only repeats certain commands. As you have seen, reload() is not one of them.

I recommend using recursion to implement the repeating reload cycles. Here is an example:

let remainingAttempts = 30;

function waitUntilTableExists() {
    let $table = Cypress.$('table');
    if ($table.length) {
        // At least one table tag was found.
        // Return a jQuery object.
        return $table;
    }

    if (--remainingAttempts) {
        cy.log('Table not found yet. Remaining attempts: ' + remainingAttempts);

        // Requesting the page to reload (F5)
        cy.reload();

        // Wait a second for the server to respond and the DOM to be present.
        return cy.wait(1000).then(() => {
            return waitUntilTableExists();
        });
    }
    throw Error('Table was not found.');
}

waitUntilTableExists().then($table => {
    cy.log('table: ' + $table.text());
});

You may be tempted to use a for or while loop, but that won't work with Cypress. This is because most commands are not executed right away. Instead, commands are asynchronous.

Perform the wait on the reload using recursion. Something like this:

function reloadPageUntilReportIsGenerated(maxAttempts=10, attempts=0) {
    if (attempts > maxAttempts) {
        throw new Error("Timed out waiting for report to be generated")
    }
    cy.get("table").then($table => {
        if ($table.children().length == 0) {  // do your condition check synchronously
            cy.reload()
            reloadPageUntilReportIsGenerated(maxAttempts, attempts+1)
        }
    })
}

Then in the test call the wait right after you trigger the loading of the report.

cy.get("trigger-report").click()  // Start report generation
reloadPageUntilReportIsGenerated()  // Wait until page has report ready

The main caveat to watch out for is the recursive waiting requires mixing asynchronous and synchronous code, so be careful or you'll end up with the synchronous code running in the wrong place (like right as the test begins). Avoid this by wrapping any synchronous calls inside the asynchronous ones using .then().

Related