auth0cypressauth0-lock

How to test single page application with Cypress and Auth0


I am having a single page application hidden behind Auth0 lock, using @auth0/auth0-spa-js. I would like to test it using Cypress, so I have decided to follow the official Auth0 blog post, as well as Johnny Reilly blog post.

I am able to successfully retrieve valid JWT token from auth0 using suggested request. I have no idea what to do with it :(

The trouble I am facing is that both of the above approaches are relying on the app to store the JWT token locally (either in cookie or localstorage). The @auth0/auth0-spa-js is, however, using a different approach, and I assume all the relevant cookies/localstorage is stored on auth0 domains.

Do you have any idea, if there is a way to get around it?

There is a similar issue reported here raised in July 2018, not really providing any solution


Solution

  • I found a resolved issue on @auth0/auth0-spa-js github. The approach suggested by cwmrowe seems to be working

    The solution is to mock the response of oauth/token endpoint with token generated on e2e test side.

    The approach seems to be working for us

    I am copying over the sample code cwmrowe has provided

    Cypress.Commands.add(
      'login',
      (username, password, appState = { target: '/' }) => {
        cy.log(`Logging in as ${username}`);
        const options = {
          method: 'POST',
          url: Cypress.env('Auth0TokenUrl'),
          body: {
            grant_type: 'password',
            username,
            password,
            audience: Cypress.env('Auth0Audience'),
            scope: 'openid profile email',
            client_id: Cypress.env('Auth0ClientId'),
            client_secret: Cypress.env('Auth0ClientSecret')
          }
        };
        cy.request(options).then(({ body }) => {
          const { access_token, expires_in, id_token } = body;
    
          cy.server();
    
          // intercept Auth0 request for token and return what we have
          cy.route({
            url: 'oauth/token',
            method: 'POST',
            response: {
              access_token,
              expires_in,
              id_token,
              token_type: 'Bearer'
            }
          });
    
          // Auth0 SPA SDK will check for value in cookie to get appState
          // and validate nonce (which has been removed for simplicity)
          const stateId = 'test';
          const encodedAppState = encodeURI(JSON.stringify(appState));
          cy.setCookie(
            `a0.spajs.txs.${stateId}`,
            `{%22appState%22:${encodedAppState}%2C%22scope%22:%22openid%20profile%20email%22%2C%22audience%22:%22default%22}`
          );
    
          const callbackUrl = `/auth/callback?code=test-code&state=${stateId}`;
          return cy.visit(callbackUrl);
        });
      }
    );
    
    declare namespace Cypress {
      interface Chainable<Subject> {
        login(
          username: string,
          password: string,
          appState?: any
        ): Chainable<Subject>;
      }
    }