简体   繁体   中英

Visit new url Cypress

I'm new to Cypress. My app as a "routing system" manually changes window.location.hash . At some point, I click on a button that changes the hash and consequently should change the page during the test. I can see a "new url" entry appearing during the execution, but how can I make cypress visit that url?

在此处输入图像描述

In few words, what the problem is: you can see I type the password and then {enter} . Running the test I can see the hash change in the address bar, but the page doesn't change in accord to the hash change.

This is the testing code

context("Workflow", () => {

    it("login", () => {

        cy.visit("http://localhost:3000/src/#login")
        cy.get("#username").type("demo").should("have.value", "demouser")
        cy.get("#password").type("demo{enter}").should("have.value", "demo") // this should redirect to "/#home"
        //cy.wait(10000)
        cy.get(".subtitle").should("have.value", "Welcome") //this line fails as ".subtitle" is an element of "/#home"
    })
})

EDIT: Following tons of failed attempts, I came up with a partially working, clunky and hacky solution. I think I shouldn't need to use reload() to solve that (there must be a better solution..), but to make it works I have to wait for all the remote requests to be done (otherwise reload() cancels them). I say partially working because you can see from the comments in the code if I try to visit #login first, then follow the redirect in #home and then change the page to #browser , the last one doesn't work (I can see the hash changing to #browser , but the page is still #home ).

import 'cypress-wait-until';

let i = 0;

context("Workflow", () => {
    it("login", () => {
        cy.server( {
            onRequest: () => {
                i++;
            },
            onResponse: () => {
                i--;
            }
        });

        cy.visit("http://localhost:3000/src/#login")
        cy.get("#username").type("demouser").should("have.value", "demouser")
        cy.get("#password").type("demouser").should("have.value", "demouser")
        cy.get("form#formLogin").submit()

        cy.waitUntil(() => i > 0)
        cy.waitUntil(() => i === 0)
        cy.reload(); // it correctly change the hash AND the page to #home!

        cy.url().should("include", "#home") 
        cy.get(".version").contains( "v2.0.0-beta") // it works!!

        cy.get("a[data-id=browser]").click({force: true}) // it correctly changes the hash to #browser
        cy.waitUntil(() => i > 0)
        cy.waitUntil(() => i === 0)
        cy.reload();

        // the hash in the address bar is #browser, but the web page is #home
    })
})

Cypress has an event called url:changed . See doc on Events here

Using this, something like this may work:

context("Workflow", () => {
    it("login", () => {

        cy.on('url:changed', url => {
            cy.location('hash').then(hash => {
                if (!url.endsWith(hash)) {
                    cy.visit(url);
                }
            });
        });

        cy.visit("http://localhost:3000/src/#login")
        cy.get("#username").type("demo").should("have.value", "demouser")
        cy.get("#password").type("demo{enter}").should("have.value", "demo") // this should redirect to "/#home"
        cy.get(".subtitle").should("have.value", "Welcome") //this line fails as ".subtitle" is an element of "/#home"

    })
})

Edit: just for troubleshooting purposes and to focus on your issue, can you try it like this without cy.location() :

context("Workflow", () => {
    it("login", () => {

        cy.on('url:changed', url => {
            cy.visit(url);
        });

        cy.visit("http://localhost:3000/src/#login")
        cy.get("#username").type("demo").should("have.value", "demouser")
        cy.get("#password").type("demo{enter}").should("have.value", "demo") // this should redirect to "/#home"
        cy.get(".subtitle").should("have.value", "Welcome") //this line fails as ".subtitle" is an element of "/#home"

    })
})

Edit: Have you tried cy.reload()

context("Workflow", () => {

    it("login", () => {

        cy.visit("http://localhost:3000/src/#login")
        cy.get("#username").type("demo").should("have.value", "demouser")
        cy.get("#password").type("demo{enter}").should("have.value", "demo") // this should redirect to "/#home"
        cy.reload();
        cy.get(".subtitle").should("have.value", "Welcome");
    })
})

There are some ways to do that. One of the basic approach is like this:

  cy.visit(`your_login_page`)
  cy.get('[data-testid="input-username"]').type(`demo`, { force: true })
  cy.get('[data-testid="input-password"]')
    .type(`demo`, {
      force: true,
    })
    .wait(1000)
    .then(() => {
      cy.location().should((loc) => {
        expect(loc.pathname).to.eq(your_new_url)
      })
    })

You should add data-testid or findByTestId to your elements with a unique id. To visit the new URL, you can use cy.visit(loc.pathname)

Thanks for all the attempts to solve, but they were all tricky workarounds to something as simple as "trigger the related listener when window.location.hash changes".

The root of the problem was a bug in Cypress . The bug on window.location.hash is present in 4.5.0 , but it has been solved somewhere between 4.5.0 and 4.12.1 .

In 4.12.1 the problem is solved.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM