8

I am trying to write end to end tests for this application with Cypress: https://app.gotphoto.com/admin/auth/login

When I visit the above url from my browswer, a login form is showing, as expected.

When I visit the above url through Cypress:

  • cypress first navigates to https://app.gotphoto.com/admin/auth/login
  • immediately afterwards I am redirected to https://app.gotphoto.com/__/ and the login form is not showing

These are two screenshots from inside Cypress:

enter image description here enter image description here

My question is: why is there a difference between how it runs in my browser and how it runs in Cypress / Cypress's browswer?

The browswer I am using is Chrome 89, both when running with and without Cypress.

The entirety of the test I am running is this:

describe('login screen', () => {
  it('logs in', () => {
    cy.visit('/admin/auth/login');
  });
});

with a cypress.json:

{
  "baseUrl": "https://app.gotphoto.com"
}

I created a repo with the above configuration so it's simple to reproduce.

Richard Matsen
  • 20,671
  • 3
  • 43
  • 77
handris
  • 1,999
  • 8
  • 27
  • 41

4 Answers4

3

The /__/ portion of https://app.gotphoto.com/__/ is called the clientRoute and is an internal configuration item in Cypress.

You can turn it off in your cypress.json configuration file

{
  ...
  "clientRoute": "/"
}

This effectively keeps your original url and allows the page to load properly.

cy.visit('https://app.gotphoto.com/admin/auth/login')
cy.get('input#username', { timeout: 10000 }).type('admin') // long timeout
                                                           // wait for page to load
cy.get('input#password').type('password')

cy.intercept('POST', 'api.getphoto.io/v4/auth/login/user').as('user')
cy.contains('button', 'Submit').click()

cy.wait('@user').then(interception => {
  // incorrect credentials
  expect(interception.response.body.detail).to.eq('Login failed!')
})

I'm not sure of any bad side effects of changing clientRoute, will post more information if I find it.

Richard Matsen
  • 20,671
  • 3
  • 43
  • 77
1

An example of logging in. Ultimately this is a bit of a hacky solution as it fails on the very first try; however, it works on any subsequent attempt.

Add the following to your command.js

// -- Visit multiple domains in one test
Cypress.Commands.add('forceVisit', url => {
  cy.window().then(win => {
    return win.open(url, '_self');
  });
});

login.spec.js

describe('login screen', () => {
  it('logs in', {
    retries: {
      runMode: 1,
      openMode: 1
    }
  }, () => {
    cy.forceVisit('https://app.gotphoto.com/admin/auth/login');
    cy.get('#username').should('exist');
  });
});

Screenshot: enter image description here

Muck
  • 68
  • 1
  • 9
0

That redirect to __/ sounds familiar to an issue I stumbled upon some time ago. I found this comment in one of Cypress' issues quite helpful.

So did you already try to use the configuration option experimentalSourceRewriting? In your cypress.json, it may look like this:

{
    "baseUrl": "https://app.gotphoto.com"
    "experimentalSourceRewriting": true
}

As it's labelled experimental, I'd recommend testing it carefully but maybe it helps a bit. I hope for the best!

0

why is there a difference between how it runs in my browser and how it runs in Cypress / Cypress's browser?

Your normal browser waits for the XHR requests to be completed and renders the final output created by whatever js magic you have written in there but cy.visit is not supposed to wait for those XHR / AJAX requests inside. It gets 200 in response and moves ahead. If you add a cypress command next to cy.visit, something like cy.get('h1'), you will notice that this command runs instantly after cy.visit, and after that, your XHR requests are resolved.

One work around here can be to use cy.intercept, for example (Cypress 6.8.0, Chrome 89):

describe("login screen", () => {
  it("logs in", () => {
    cy.intercept({
      method: "GET",
      url: "admin/version/master/index.html"
    }).as("indexHTML"); // Similarly add other internal xhr requests

    cy.visit("/admin/auth/login");

    cy.wait("@indexHTML").then(interception => {
      expect(interception.response.statusCode).to.be.eq(200);
    });
  });
});

Output: enter image description here It basically waits for your internal XHR requests to finish and allows you to play with the request and responses once they are resolved.

This issue will help you debug further: https://github.com/cypress-io/cypress/issues/4383

Also, this /__/ has no hand in rendering the blank page IMO.

Sagar Ganiga
  • 430
  • 4
  • 8
  • Usually you can achieve the same effect by `cy.get()` an element on the loaded page, with a suitable timeout if the page load is slow. Unfortunately no amount of waiting is fixing this problem. –  Mar 21 '21 at 21:45
  • I tried waiting, does not resolve the issue. I guess they will have to use something specific to the framework they are using. For example, for react cypress has https://github.com/cypress-io/cypress/tree/master/npm/react – Sagar Ganiga Mar 22 '21 at 07:09
  • 1
    Indeed, `cy.wait("@indexHTML")` is waiting, but does not work. –  Mar 22 '21 at 07:52