End-to-End Testing with Cypress and Auth0

Thanks a lot for sharing that @sirsroger!

Since version 1.7.0 auth0-spa-js has been release with the Local Storage caching mechanism feature there is a new option to address this issue. If the auth0 client is defined to use local storage cache ( createAuth0Client({cacheLocation: 'localstorage'}) ) instead of in-memory one there is no need to deal with either stubbing XHR request or creating cookies - the only thing is to create a proper cache entry in local storage.

below you can find a working typescript example

import jwt_decode from 'jwt-decode';

declare global {
  // eslint-disable-next-line @typescript-eslint/no-namespace
  namespace Cypress {
    interface Chainable<Subject> {
      login(username: string, password: string): Chainable<Subject>;
    }
  }
}

Cypress.Commands.add('login', (username: string, password: string) => {
  cy.log(`Logging in as ${username}`);
  const client_id = Cypress.env('auth_client_id');
  const client_secret = Cypress.env('auth_client_secret');
  const audience = Cypress.env('auth_audience');
  const scope = 'openid profile email';

  const options = {
    method: 'POST',
    url: Cypress.env('auth_url'),
    body: {
      grant_type: 'password',
      username,
      password,
      audience,
      scope,
      client_id,
      client_secret,
    },
  };
  cy.request(options).then(({ body }) => {
    const { access_token, expires_in, id_token } = body;
    const key = `@@auth0spajs@@::${client_id}::${audience}::${scope}`;
    const auth0Cache = {
      body: {
        client_id,
        access_token,
        id_token,
        scope,
        expires_in,
        decodedToken: {
          user: jwt_decode(id_token),
        },
      },
      expiresAt: Math.floor(Date.now() / 1000) + expires_in,
    };
    window.localStorage.setItem(key, JSON.stringify(auth0Cache));
  });
});

export {};

I hope it helps you :slight_smile:

4 Likes

Thanks a lot @dobrek for sharing it with the rest of community!

Hello @dobrek do you have some example how you are using your ‘login’ method in the tests?
I am trying to use your solution. The proper cache entry is created in local storage but app page is not loaded :frowning:

It could be used in the same way as any other cypress command

describe('Test', () => {
  it('should get access to restricted page', () => {
    cy.login(Cypress.env('AUTH_USERNAME'), Cypress.env('AUTH_PASSWORD'));
    cy.visit('/restricted')
    cy.get('h1').contains('Restricted')
  });
});

or as chained execution

describe('Test', () => {
    cy.login(Cypress.env('AUTH_USERNAME'), Cypress.env('AUTH_PASSWORD')).then(() => {
        cy.visit('/restricted')
        cy.get('h1').contains('Restricted')
    });
});
2 Likes

Thank you for the quick response :slight_smile: I will check once again my solution, maybe not everything is set properly in local storage.

1 Like

Let us know if you have any other questions Karolina!

1 Like

@konrad.sopala
It turns out that there was a problem on our side. After we rewrite some things in authentication I am able to use @dobrek solution :slight_smile:
So, right now, no more questions :slight_smile:
Thank you guys!

1 Like

Nie ma problemu! We’re here for you!

1 Like

@konrad.sopala Auth0 has any update, or recommended way of dealing with this yet? I have tried all things, that people commented here, but no success.

I am using auth0-spa-js 1.10.0 and react 16.13.1

Thank @dobrek worked fine for me and save my life :wink:

1 Like

Glad to hear that @matinfo!

I’m using auth0-react hook useAuth0.
I successfully get the access_token, expires_in, and id_token, but I could use some guidance on how to use them to actually have the hook/Auth0Provider detect those and set the required variables.

thanks!

1 Like

I’m trying to login to auth0 during a cypress test using auth0-react. I’ve followed this guide -

That guide does not use auth0-react and has a custom state/auth handler which updates once the { access_token, expires_in, id_token } are received.

Is there any simple way to update the auth0-react login state once the tokens are received?

Ideally, I’d be able to use some endpoint to receive the usual code which is given when logging in with the UI. For example, receive code xxx and redirect to:

http://localhost:3000/dashboard?code=xxx&state=yyy

auth0-react would then update the login state automatically when it parses the URL.

Someone asks the same question in a comment on the post but there isn’t a response:

"I would like to be able to implement a Cypress “login” command that exercises my callback with a code (i.e. authorization code) that would typically be acquired via OAuth exchange. Is there an Auth0 API endpoint that allows me to get a code that I can then use for my callback e.g. https://mydomain.com/callback?code=abcd1234?"

Any ideas?

2 Likes

Moving your message here as this thread is for issues and questions regarding this blog article. Thank you!

1 Like

I’m looking to do the same. Did you find solution with auth0-react?

Not sure if this will be helpful to some other people.

To get this working inside our application (we’re using auth0-react, although this is irrelevant), I ended up making a separate auth0 app for testing that allows login via password grant. I then implemented a solution very similar to what was suggested here End-to-End Testing with Cypress and Auth0

I set the cache mechanism for auth0-react via ENV var, and set it to localstorage before starting the server for cypress tests. I make a login call to auth0 in a before hook, and save the localstorage state and restore it in beforeEach hooks to avoid having to make multiple calls to auth0.

1 Like

Thanks a lot for sharing that with the rest of community @tallyoh!

I wanted to follow up and let everyone know that we are working on a new version. I’ll be sure to share more details as they become available! Stay tuned :slightly_smiling_face:

2 Likes

@James.Morrison maybe you now when the new version of the tutorial will be available?

1 Like