11
votes

I'm trying to make a programmatic login with Cypress before each test. My tokens are persisted in localStorage. If I alter it synchronously, i.e. simpy doing localStorage.setItem without involving cy.request it works fine. However, I would like to use my auth server (http://localhost:3004/login below) to generate tokens.

The token is fetched correctly from the server, but as soon as I use the command below along with cy.visit('/') I get "Failed to visit localhost:8080 - We attempted to make an http request to this URL but the request failed without a response" (see full log below).

As far as I can tell, this is the correct approach when using an auth server for headless authentication. What did I miss?

commands.js

Cypress.Commands.add('login', () => {
  cy.request({
    method: 'POST',
    url: `http://localhost:3004/login`,
    body: {
      username: '[email protected]',
      password: '123'
    }
  }).its('body').then((body) => {
    const vuexData = { user: { authenticationData: { token: body.token } } }
    window.localStorage.setItem('vuex', JSON.stringify(vuexData))
  })
})

test.js

describe('A test', () => {
  beforeEach(() => {
    cy.login()
  })

  it('works', () => {
    cy.visit('/')
    cy.get('h1').contains('All Books')
  })
})

CypressError: cy.visit() failed trying to load:

http://localhost:8080/

We attempted to make an http request to this URL but the request failed without a response.

We received this error at the network level:

Error: connect ECONNREFUSED ::1:8080

Common situations why this would fail: - you don't have internet access - you forgot to run / boot your web server - your web server isn't accessible - you have weird network configuration settings on your computer

The stack trace for this error is:

Error: connect ECONNREFUSED ::1:8080 at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1056:14)

2
Failing the same thingTree Nguyen
If I use a generic version of your code, logging vuexData within .its('body').then((body), it('works', () => {, and the Vue app mounted() they all have correct values and logs occur in correct order (hitting typicode with the POST). The only thing I can suggest is to log body after the POST and see if it has the correct form. Elsewise, how does the Vue app use the token?Richard Matsen
@Johan I ended up with some quick workaround so I can get over this is by getting a token from logged in test user then hard-coded it into the test. It will certain be a very bad thing to do, but it lets me get on with writing real codeTree Nguyen
If you fake out a login using fixtures, then no interaction with an authenticated API server would work.Cory Danielson
I have set up an example app just as you have described and Cypress works perfectly. Token is written to local storage before any call to service on 8080. Are you sure there is no problem in your app running on 8080. Replace your app with a simple index.html file with the h1 header present (or not) and try re-run the test.jeeves

2 Answers

0
votes

Ok, a couple of mistakes here.

  1. Replace cy.route() by cy.intercept(), since the earlier one was recently deprecated and replace by the later one.
  2. Check the correct syntax for using cy.intercept() since it's a bit different from cy.route()
  3. I'm assuming that you're trying to bypass some sort of authentication. If all your app requires to consider a user "authenticated" is to have those information on the local storage, you don't even need to perform the POST request, but, if you do, then:
  4. Check the usage of cy.intercept() for handling (and stubbing) the request and response objects that are related to your XHR request.
  5. For setting the local storage on your Cypress window, you'll need to use the cy.window() command.
-2
votes

A couple of things. I've never used cypress but any network calls are going to be async. None of your functions above are returning the promises generated from your functions. So where you create your login command. You need to return the promise from that function and you need to await it in your beforeEach function. Might be the cause of your problem, maybe not.

Is it possible you have a bug in you application where you are timing out because you have an unauthenticated request to the service running on port 8080. Looking at the code as it stands, you are going to call visit (your test) before your beforeEach has completed. It is very likely that the data is not in local storage by the time you hit your test.

Having a quick read through the documentation on cypress, it looks like cypress tries to figure out where your service is located. The other thing which it looks like is that it appends the url defined in the request to the baseUrl configured. Do you actually see the auth request come in on your auth service?