最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Visit new url Cypress - Stack Overflow

programmeradmin2浏览0评论

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
    })
})

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
    })
})
Share Improve this question edited May 9, 2020 at 21:26 alfredopacino asked Apr 30, 2020 at 20:05 alfredopacinoalfredopacino 3,2419 gold badges47 silver badges79 bronze badges 12
  • 1 Have you tried cy.visit()? – jmargolisvt Commented Apr 30, 2020 at 20:12
  • cy.visit() takes the url as argument. I don't need that. I simply need to visit the page the menu button is pointing to. – alfredopacino Commented Apr 30, 2020 at 21:03
  • So you're clicking a button, and it manually changes the anchor AKA the window.location.hash. When you manually click on the button in the webpage, are you redirected to the anchor? – natn2323 Commented May 2, 2020 at 6:17
  • of course it works, the website itself works fine. The whole problem is when I run it in cypress, I click a button using cy.find("#mybutton").click() and cypress simply doesn't change the page. – alfredopacino Commented May 2, 2020 at 13:19
  • 1 You said that you clicked a button, but that is not shown on the log above. Probably because cy.find("#mybutton") is invalid syntax, see here. It would be much more helpful to show the test code. – Richard Matsen Commented May 5, 2020 at 12:22
 |  Show 7 more comments

3 Answers 3

Reset to default 8 +25

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");
    })
})

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.

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)

发布评论

评论列表(0)

  1. 暂无评论