New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to wait for page finish reloading after click? #1805
Comments
Hey @kkorus I think this FAQ should help answer your question, but basically https://on.cypress.io/using-cypress-faq#How-do-I-wait-for-my-application-to-load Edit by @jennifer-shehane - Added link to FAQ. Sorry y'all 😬 |
|
A workaround I found was
|
@tivnet yeah, I saw that, but it looks like a hack for me rather then solution. |
Cypress automatically detects and waits for the page to finish loading. You don't need to be concerned with it. It will pause command execution, prevent them from timing out, and then begin re-running them once the page transition is complete. |
The script below: Cypress.config(
{
"baseUrl": "https://www.artbylena.com"
}
);
describe("Test", () => {
const DOM_PRICE_CURRENCY_SYMBOL = ".woocommerce-Price-amount > .woocommerce-Price-currencySymbol";
it('Switches currencies', () => {
cy.visit("/paintings/");
cy.get(DOM_PRICE_CURRENCY_SYMBOL).contains("US$");
cy.get('.wpglobus-currency-selector').select("CAD");
// cy.wait(2000);
cy.get(DOM_PRICE_CURRENCY_SYMBOL).contains("C$");
});
}); fails without and works with it: |
@tivnet I faced this sort of thing already, and even though it works setting a Have also in mind that Hope this is useful info |
@davidzambrana P.S. |
In my case for example when I had to check a field that changed its value after some action, I also had to check that a toast showed up, so when I triggered the click, I included in a |
@tivnet excellent example - in your test, you need something observable that shows how the new page is different after reload. Since the url stays the same, the only difference is that the new page sets the cookie /// <reference types="cypress" />
describe("Test", () => {
const DOM_PRICE_CURRENCY_SYMBOL = ".woocommerce-Price-amount > .woocommerce-Price-currencySymbol";
it('Switches currencies', () => {
cy.visit("/paintings/");
cy.contains(DOM_PRICE_CURRENCY_SYMBOL, "US$");
cy.get('.wpglobus-currency-selector').select("CAD");
// cy.wait(2000);
cy.getCookie('wpglobus-forced_currency').should('have.property', 'value', 'CAD')
cy.contains(DOM_PRICE_CURRENCY_SYMBOL, "C$");
});
}); The GUI shows how this assertion only passes after the page reloads @davidzambrana Bonus: notice |
@bahmutov Thanks, Gleb, it works perfectly and even adds an additional assertion for the cookie value. Don't you think that Cypress should wait for the page reload anyway? It knows that the page is being reloaded, but tries to search the old DOM. Intellisense works in *Storm IDE without additional setup. Thanks for the GREAT TESTING SUITE 🥇 |
@tivnet so the problem is that Cypress cannot know how long to wait for potential page reload. Maybe the page will reload in 50ms or 500ms or 5 seconds - there is no way to predict this. So when it can grab the element right away (and it is found!) then it just goes with that. Glad to hear about WebStorm IDE doing good job understanding types, nice. For custom commands you need to describe them, which is extra work (I prefer just using functions instead of adding custom commands). See https://github.com/cypress-io/add-cypress-custom-command-in-typescript Thanks a lot for positive feedback, appreciate this |
Sorry, I failed to paste the FAQ link on loading 😬 https://on.cypress.io/using-cypress-faq#How-do-I-wait-for-my-application-to-load |
@jindrake Providing the test code run would be helpful. Also try asking in our community chat, searching our existing GitHub issues, reading through our documentation, or searching Stack Overflow for relevant answers. |
I am also seeing the same issue as @jindrake mentioned In my application SessionID is set in local storage after user clicks on login I have Code Like This:
in the step definition of " I navigate to addresses" i am checking if session is not null or not using this code
The Assertion is being executed right away with out waiting for first step |
Hey @darasandeep91, could you provide the full Cypress test code that is being run? The first and second step? |
Here are the steps i am trying to perform:
when i run the test even before the login step i am getting the error stating expected null not to be null Given(/^I have logged in to app as "([^"]*)"$/, (userType) => {
cy.fixture('selfcareUsers').then((user) => {
const { [userType]: { username } } = user;
const { [userType]: { password } } = user;
cy.Login(username, password);
});
});
Given(/^I navigate to "([^"]*)" page$/, (pageName) => {
expect(localstorage.read('CD-SessionID')).not.to.be.null;
cy.fixture('pages').then((pages) => {
cy.visit((pages[pageName]));
});
}); Here is code for Cy.login() Cypress.Commands.add('Login', (userName, password, environment, businessUnit) => {
cy.visit('/login');
setEnvironment(environment, businessUnit);
cy.get('#login').type(userName);
cy.get('#password').type(password);
cy.get('button:contains("Sign In")').click();
}); |
I believe the |
The real solution to the problem in the original post is this: cy.click('#someButtonToNavigateOnNewPage');
cy.location('pathname', {timeout: 10000})
.should('include', '/newPage');
cy.click('#YouAreOnNewPage'); @jennifer-shehane Not sure why you link to docs about how |
I have the same problem except that I don't know the path ahead of time. I'm submitting a form that creates a new object whose id is in the location url, so I can't even use @msty's solution. The only option I have is to slap an arbitrary cy.wait() in there. Why isn't there a generic, 'wait until page loads' function? Or am I missing something? |
I'm new-ish to cypress but have been using it for a few months and this is still the thing I struggle with the most. I think testing that a page loads (refresh, nagivation, whatever) is something that should be easily testable. For example, if the application triggers a refresh upon user selection of a select menu, you should be able to easily test that it occurs. So like: cy.get('[data-test="shipping-select"]').select("UPS");
cy.pageRefreshed(); // <-- why not? As mentioned before, I'm supposed to be looking for something that changed in the DOM rather than looking for the page refresh itself. But in this case, there is nothing different. If you try to assert that "UPS" is selected it will be true both before and after the page is refreshed. Perhaps there is a way to do this or perhaps I am indulging in an anti-pattern. |
Here is a solution for anyone wondering what to do if the URL stays the same, and the page itself stays the same: add a property to the Example: here is the page markup <body>
<button id="button">Click to reload</button>
<script>
document.getElementById('button').addEventListener('click', () => {
console.log('clicked')
setTimeout(() => {
console.log('reloading page after delay')
location.reload()
}, 2000)
})
</script>
</body> and here is the test it('reloads', () => {
cy.visit('index.html')
// mark our window object to "know" when it gets reloaded
cy.window().then(w => w.beforeReload = true)
// initially the new property is there
cy.window().should('have.prop', 'beforeReload', true)
cy.get('#button').click()
// after reload the property should be gone
cy.window().should('not.have.prop', 'beforeReload')
}) Notice how the test waits as long as necessary using |
Nice - that's a great idea. Thanks for cypress, it's really alot of fun to work with! |
I've used the @msty solution with one modification, I've to check that the body is there before to access anything cy.click('#someButtonToNavigateOnNewPage');
cy.location('pathname', {timeout: 10000})
.should('include', '/newPage');
cy.get('body'); |
I also used the @msty solution but with a little bit of modification, which I think it a bit more specific and nice since you can do whatever logic you want with the function. cy.location({ timeout: 15000 }).should(($url) => {
expect($url).to.match(/http:\/\/localhost:3000\/event\/1dc49a776b63be235aecccfd\/1573165592600\/payment\/v2\/.{0,}\/confirmation/)
}); And I use the regex |
Could be a feature request a method like |
I met the same problem, and I use cy.wait() https://docs.cypress.io/api/commands/wait.html#Syntax solved it. |
Here's another solution from the Cypress docs: // Wait for the route aliased as 'getAccount' to respond
// without changing or stubbing its response
cy.server()
cy.route('/accounts/*').as('getAccount')
cy.visit('/accounts/123') // or, in our case: cy.get('.submit-button').click()
cy.wait('@getAccount').then((xhr) => {
// Make assertions here
}) |
My solution to check for a reload ist: cy.window().its('performance.navigation.type').should('eq', 0); // checks for 'TYPE_NAVIGATE'
doReloadStuff();
cy.window().its('performance.navigation.type').should('eq', 1); // checks for 'TYPE_RELOAD' Look here for further details: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigation/type., it's deprecated but still works. The newer option |
@vitorpiovezam There is an open issue proposing a 'waitForNetworkIdle' feature here: #1773 |
With cypress, cy.visit() can be used to wait for a page to load. More info cypress-io/cypress#1805.
Its is not happening in my case I have to give wait cy.wait() to avoid timeout issue to navigate to another page after a click button . |
My use case:
what is my best option? Im using svelte btw |
If it's helpful to anyone else, I adapted #1805 (comment) into this custom command: /**
* Given a function with some commands that cause the page to change or even
* just reload, this command runs the command then waits for that page load.
*
* Ideally this command should be used sparingly, instead preferring to use
* matching functionality to wait for reload.
*
* Adapted from:
* https://github.com/cypress-io/cypress/issues/1805#issuecomment-525482440
*/
Cypress.Commands.add("waitForPageLoadAfter", block => {
// mark our window object to "know" when it gets reloaded
cy.window().then(win => {
// eslint-disable-next-line no-param-reassign
win.beforeReload = true;
});
// initially the new property is there
cy.window().should("have.prop", "beforeReload", true);
// Run the code that triggers the page reload/change
block();
// after reload the property should be gone
cy.window().should("not.have.prop", "beforeReload");
}); Then use it like: cy.waitForPageLoadAfter(() => { cy.contains("button", "Click here to reload"); });
cy.contains("page reloaded!").should("exist"); thanks, @bahmutov ! |
How about: In And:
|
@emilong, by adding a timeout, it's possible to have a longer running request:
|
This worked for me, although I still rather have built-in function, because Cypress is able to know when a page refresh is being made. |
@kkoomen and @rzegnam what you are describing is built into Cypress already, see https://on.cypress.io/location cy.location('pathname').should('equal', '/newPage') |
@bahmutov I was talking about the part where cypress should wait for the page to be reloaded. That part hasn't been solved yet natively by Cypress, right? |
No, so it all requires just observing something external like URL or even a property, no need to use |
Anyone looking answers to this question, implement your own wait until behavior as you do in puppeteer, or webdriver. When going through the intro & docs it gave an impression that cypress abstracted the behavior, by waiting till all the network request completes, or wait till a given DOM node is loaded. But its not the case. As discussed in this question, you have add additional logic to handle this anyway. Also, the logic with setting a property in the window object is not possible if you are writing an automated test for an existing application. And this is a bad hack. |
It's really frustrating that such a simple and basic thing as click on an element and wait for the next page to load is so complicated with Cypress. |
Try this: |
In my case, the only solution to mimic an 'async/await' behavior was to increase execTimeout in |
I know that this is REALLY situational but in my version of Vue setup with how my company does, the root html element has a class nprogress-busy that shows during network calls. This is easier for me than checking for a spinner or a skeleton element. Example
If not, usually other JS frameworks have similar tricks. My previous tests were for an Angular project and there was some specific state you could check on whether calls were finished. If not, waiting for spinner elements or skeleton elements to disappear was working for me previously. Not good but it gets the job done. |
Looks like only initial cy.visit('/page');
doSomeActions();
assertResults();
// check results persist after that
cy.visit('/page'); // THIS ONE IS NOT BLOCKING
assertResults(); // SO THIS COULD PASS IMMEDIATELY FOR THE CURRENT PAGE |
Hi, for my side, worked this: |
The hack is to change the default timeout for cypress, bydefault the timeout for cypress task is 4s, you can change it in cypress.config.js and you don't have to use cy.wait() for that.
now each line will run for either the test condition match or 10s and not like the wait() function which wait for exactly the given time. |
I got form and when I trigger click on submit button this cause to refresh current page. After that I would like to do some assertions. How I know that page finished refreshing and I can start to searching an element to do assertions?
Looking for something like
page.waitForNavigation
in Puppeteer.The text was updated successfully, but these errors were encountered: