Reputation: 43569
Cypress offers a simple way to test for server-side redirects using request:
cy.request({
url: `/dashboard/`,
followRedirect: false, // turn off following redirects
}).then((resp) => {
expect(resp.redirectedToUrl).to.eq('http://example.com/session/new')
})
However this doesn't work for client-side redirects because the page is loaded successfully before the redirect happens, meaning the response is for the page, not for the redirect.
How can I test a client-side redirect?
I need a way of catching the redirect and verifying that:
Note:
window.location.href = url
Upvotes: 9
Views: 3892
Reputation:
Gleb Bahmutov has an approach at Deal with window.location.replace, which renames window.location
in the source to window.__location
which is effectively the stub.
It uses cy.intercept()
to modify the loading page before it hits the browser, i.e before window.location
is instantiated and becomes a totally immutable/incorruptible object.
it('replaces', () => {
cy.on('window:before:load', (win) => {
win.__location = { // set up the stub
replace: cy.stub().as('replace')
}
})
cy.intercept('GET', 'index.html', (req) => { // catch the page as it loads
req.continue(res => {
res.body = res.body.replaceAll(
'window.location.replace', 'window.__location.replace')
})
}).as('index')
cy.visit('index.html')
cy.wait('@index')
cy.contains('h1', 'First page')
cy.get('@replace').should('have.been.calledOnceWith', 'https://www.cypress.io')
})
This stubs replace
, but the same should work for the href
setter.
Upvotes: 1
Reputation: 776
Here is what I have found as the only was to detect a successful redirect client side if it is to a third-party website. JavaScript has a handy-dandy function called window.open(). There are many things that you can do with it including redirecting the webpage. This can be done by setting the target to _self or to _top. By using a while loop, you are running code as quickly as you can. Here is a rough-draft of how I would record a client-side redirect.
var redirectURL = 'https://www.example.com/',
redirectWindow = window.open(redirectURL, '_top'),
redirected = false,
count = 0;
while(true) {
if (redirectWindow.document.readyState === 'complete') {
redirected = true;
//Your code here. I am just logging that it is in the process of redirection.
console.log('redirecting')
break;
}
if (count > 2000) {
redirected = false;
break;
}
count++
}
if (redirected == false) {
console.log('Error: Redirect Failed');
}
Upvotes: 0
Reputation: 43569
Update: This isn't solid. I've just done some refactoring and it seems that even this solution is flawed. It is possible for the redirect to happen in between cypress visiting the page and triggering the cy.wait
so the test ends up waiting for something that has already happened. The below might still work for you depending on when your redirect is triggered, but if it's triggered on initialisation, it appears this will not work.
Not really loving this solution as the redirect still happens (I haven't found a way to cancel it), but it at least tests that the redirect happens, and allows me to check the query:
cy.intercept({ pathname: `/sessions/new` }).as(`loginRedirect`)
cy.visit(`/dashboard/`)
cy.location().then(($location) => {
cy.wait(`@loginRedirect`).then(($interceptor) => {
const { query } = urlParse($interceptor.request.url)
expect(query).to.equal(`?token=true&redirect=${$location.href}`)
})
})
Note: route2
changed to intercept
in v6.
Upvotes: 2