E2E Testing an App with Clerk Authentication in Cypress

☕ 1 min read

Background: Clerk is a hosted authentication and user management product.


I recently started writing E2E tests in Cypress for an app that uses Clerk for authentication, and there wasn’t anything out there to guide me, so here’s what I ended up with after fiddling with it for a bit.

(Note: In my case, this is a Next.js app using Clerk’s Next.js SDK, but my understanding is that this code will work everywhere, because their client SDKs all ultimately use ClerkJS under the hood.)

I wrote a custom Cypress command that waits for Clerk to load, signs the user out if they aren’t signed out already, and then signs in with test credentials (see here for how you can set these so that they’re accessible via Cypress.env()).

Cypress.Commands.add(`initializeAuth`, () => {
  cy.log(`Initializing auth state.`);

  cy.visit(`/`);

  cy.window()
    .should((window) => {
      expect(window).to.not.have.property(`Clerk`, undefined);
      expect(window.Clerk.isReady()).to.eq(true);
    })
    .then(async (window) => {
      await window.Clerk.signOut();
      await window.Clerk.client.signIn.create({
        identifier: Cypress.env(`TEST_USER_IDENTIFIER`),
        password: Cypress.env(`TEST_USER_PASSWORD`),
      });
    });
});

If you’re using TypeScript to write your tests (which I recommend!), you’ll also want to add this command to your custom command types.

declare global {
  namespace Cypress {
    interface Chainable {
      /**
       * Initialize auth to a state where you're
       * logged in as the test user.
       *
       * @example cy.initializeAuth()
       */
      initializeAuth(): Chainable<void>;
    }
  }
}

Ultimately, you’ll probably want to use this command in a before or beforeEach hook to reset the auth state before every test, like so:

describe(`Test Page`, () => {
  beforeEach(() => {
    cy.resetDatabase(); // another custom command
    cy.initializeAuth();
  });

  // ... tests go here
});

Happy testing! Please let me know if you run into problems with this approach.

Hey, thanks for reading all the way through! If you'd like to get in touch or keep up with what I'm working on, here's where you can find me on the usual places.