TutorialsProgrammatic Authentication with Firebase and Cypress

Testing Cypress can require your test users sign-in programmatically. In this article, we show you how to sign in users with Firebase and Cypress without using the UI.

·4 min read
Cover Image for Programmatic Authentication with Firebase and Cypress

While Cypress has greatly simplified E2E testing for developers, it can still be tricky at times. For example, a best practice while running E2E testing is bypassing the UI when testing pages behind user authentication.

The Cypress team, in particular, has long advocated for programmatically authenticating users when testing code not related to the authentication flow. For example, if you are testing your Dashboard code, there is no need to use the UI to authenticate your users: this will only result in slower, heavier and more flaky E2E tests.

In this post, we show you how to sign in programmatically with Firebase Authentication to improve the speed of your Cypress tests and increase their reliability.

Adding a Cypress command to sign-in programmatically

Cypress allows us to write global commands that we can access using the cy variable, which is globally available in all our Cypress tests.

To do so, we will extend Cypress commands with a new command we will name signIn, and will be available to us using cy.signIn(). Neat, isn't it?

First of all, we want to play nice with Typescript. That means we extend the Typescript's interface in a filename we name global.d.ts:

namespace Cypress {
    interface Chainable {
      signIn(
        redirectPath?: string,
        credentials?: { email: string; password: string }
      ): void;
    }
  }
}

Now, we can extend Cypress with a custom command named signIn. To do so, we add a command using the method Cypress.Commands.add:

Cypress.Commands.add(
  'signIn',
  (
    redirectPath = '/',
    credentials = {
      email: Cypress.env(`EMAIL`) as string,
      password: Cypress.env(`PASSWORD`) as string,
    }
  ) => {
    // body
  }
);

The above function takes two parameters:

  1. A path where to redirect users after signing in
  2. The user credentials, but by providing some default values using environment variables

Let's now write the body of the function:

// preserve the session cookie between tests
// otherwise the user will get logged out
Cypress.Cookies.defaults({
  preserve: ['session'],
});

// the function we will define to sign users in
signInProgrammatically(credentials); // <--- implementation is below

// after sign-in, we redirect the users to the provided path
cy.visit(redirectPath);

Using the Firebase Auth SDK to authenticate users in Cypress E2E tests

To sign our testing users in without having to interact with the application's UI, we will use the Firebase SDK.

Connecting to the Firebase Auth Emulator

Of course, when running tests, we will be connecting to the Firebase Emulator.

Below is a function getAuth that will initialize the Firebase SDK and return an instance of the Firebase Auth SDK connected to the local Firebase Emulator:

import {
  Auth,
  connectAuthEmulator,
  initializeAuth,
  signInWithEmailAndPassword,
  UserCredential,
  indexedDBLocalPersistence,
} from 'firebase/auth';

function getAuthEmulatorHost() {
  const host = Cypress.env('NEXT_PUBLIC_FIREBASE_EMULATOR_HOST') as string;
  const port = Cypress.env('NEXT_PUBLIC_FIREBASE_AUTH_EMULATOR_PORT') as string;

  return ['http://', host, ':', port].join('');
}

let auth: Auth;

function getAuth() {
  const app = createFirebaseApp();

  auth =
    auth ||
    initializeAuth(app, {
      persistence: indexedDBLocalPersistence,
    });

  connectAuthEmulator(auth, getAuthEmulatorHost());

  return auth;
}

Signing users in

Now that we can create an instance of the Firebase Auth SDK connected to the emulators, we can use it to sign users in programmatically:

export function signInProgrammatically({
  email,
  password,
}: {
  email: string;
  password: string;
}) {
  const auth = getAuth();

  const signIn = signInWithEmailAndPassword(
    auth, 
    email, 
    password
  )
  .catch((e) => {
    cy.log(`User could not sign in programmatically!`);
    console.error(e);
  });

  return cy.wrap(signIn);
}

Finally, the signInProgrammatically function completes the cy.signIn() command defined in the beginning.

Writing a Test that signs users in programmatically

Whenever you write tests that require users to be signed in, you can write the below:

describe(`Create Invite`, () => {
  const email = `invited-member@makerkit.dev`;

  before(() => {
    cy.signIn(`/settings/organization/members`);
  });

  // your tests go here
});

As you can see, we can pass any path to the signIn function: after signing in, we redirect the users directly to that page, rather than having to use the UI. This will dramatically improve your E2E tests' speed and make them more reliable. Regardless, no need to test the authentication page over and over!


Stay informed with our latest resources for building a SaaS

Subscribe to our newsletter to receive updatesor

Read more about
Tutorials

Cover Image for Creating a Waitlist with Firebase Auth

Creating a Waitlist with Firebase Auth

·3 min read
Implement a waitlist sign-up with Firebase Auth and allow sign-ins in batches to your SaaS
Cover Image for Using ElasticSearch with Next.js

Using ElasticSearch with Next.js

·8 min read
In this article, we share how to use ElasticSearch with Next.js to index your Firestore documents and make them searchable.
Cover Image for Using Firestore in Firebase Storage Rules

Using Firestore in Firebase Storage Rules

·3 min read
Firebase Storage now allows you to use Firestore queries to in your security rules. Here is all you need to know!
Cover Image for Turn your Next.js application into a PWA

Turn your Next.js application into a PWA

·4 min read
PWA can make your app look native, faster, updatable and offline-ready. In this post, we learn how to make a PWA with a Next.js application.
Cover Image for Email Link Authentication with Firebase and Next.js

Email Link Authentication with Firebase and Next.js

·4 min read
Learn how to add Email Link authentication to your SaaS application with Firebase Auth and Next.js
Cover Image for Walkthrough: Starting a Makerkit project with Firebase and Next.js

Walkthrough: Starting a Makerkit project with Firebase and Next.js

·9 min read
This walkthrough is a summary of the documentation to quickly bootstrapping a SaaS project with Makerkit