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

javascript - How can I test a client-side redirect to a 3rd party site with Cypress? - Stack Overflow

programmeradmin5浏览0评论

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

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:

  • it occurred
  • was to the correct URL.

Note:

  • I don't want to follow the redirect away from the app that is being tested. I'm not testing the whole auth flow. I just need to know there was a redirect.
  • I can't change this auth flow. The redirect is unavoidable.
  • The redirect happens during initialisation, not as a result of any user interaction.
  • The redirect uses: window.location.href = url
  • See my answer below for an attempt at resolving this.

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./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:

  • it occurred
  • was to the correct URL.

Note:

  • I don't want to follow the redirect away from the app that is being tested. I'm not testing the whole auth flow. I just need to know there was a redirect.
  • I can't change this auth flow. The redirect is unavoidable.
  • The redirect happens during initialisation, not as a result of any user interaction.
  • The redirect uses: window.location.href = url
  • See my answer below for an attempt at resolving this.
Share Improve this question edited Dec 3, 2020 at 14:39 Undistraction asked Nov 30, 2020 at 12:52 UndistractionUndistraction 43.4k63 gold badges206 silver badges336 bronze badges 3
  • Is the redirect to another page on your website? – myjobistobehappy Commented Dec 10, 2020 at 4:49
  • @myjobistobehappy No. 'How can I test a client-side redirect to a 3rd party site with Cypress?' – Undistraction Commented Dec 10, 2020 at 16:06
  • I think I found a solution for client side. I will make it an answer in a little. – myjobistobehappy Commented Dec 10, 2020 at 21:48
Add a ment  | 

3 Answers 3

Reset to default 2

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.

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 bees 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.

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./',
redirectWindow = window.open(redirectURL, '_top'),
redirected = false,
count = 0;

while(true) {
    if (redirectWindow.document.readyState === 'plete') {
        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');
}
发布评论

评论列表(0)

  1. 暂无评论