Flutter Firebase auth testing

Test your authentication functions with firebase

Fri, 02 Feb 2024

This one isn’t going to be too pretty and will more so give you guidance to get started. Unit testing firebase auth was not a fun time. I couldn’t find any clear up to date instructions on how to properly unit test so I made this to hopefully get you started.

There will be two files, signinscreen.dart which is where I have my auth functions and sign in screen widget. auth.dart under my tests section. I’ll mostly be giving you a template to use against the functions and will cover testing the actual widgets later

We’re going to make tests for these functions

  Future<void> signInWithEmailPassword(
      dynamic auth, String? email, String? password) async {
    try {
      await auth.signInWithEmailAndPassword(
          email: email ?? "", password: password ?? "");
    } on FirebaseAuthException catch (e) {
      print(e.message);
      if (e.code == 'user-not-found') {
        print('No user found for that email.');
        if (!Platform.environment.containsKey('FLUTTER_TEST')) {
          showToast("No user found for that email.", ToastType.ERROR,
              location: ToastGravity.BOTTOM);
        }
      } else if (e.code == 'wrong-password') {
        print('Wrong password provided for that user.');
        if (!Platform.environment.containsKey('FLUTTER_TEST')) {
          showToast("Wrong password provided for that user.", ToastType.ERROR,
              location: ToastGravity.BOTTOM);
        }
      }
    }
  }

  Future<void> signInAsDev(dynamic auth, bool useMain) async {
    try {
      final String devUser =
          useMain ? "test1@example.com" : "test2@example.com";
      await auth.signInWithEmailAndPassword(
          email: devUser, password: "Abcd_1234!");
    } catch (e) {
      print(e);
    }
  }

  signInWithGoogle() async {
    try {
      // Trigger the authentication flow
      final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();

      // Obtain the auth details from the request
      final GoogleSignInAuthentication? googleAuth =
          await googleUser?.authentication;

      // Create a new credential
      final credential = GoogleAuthProvider.credential(
        accessToken: googleAuth?.accessToken,
        idToken: googleAuth?.idToken,
      );

      await FirebaseAuth.instance.signInWithCredential(credential);
    } catch (e) {
      print(e);
    }
  }

  Future<void> signUpWithEmail(
      dynamic auth, String? email, String? password, String? fullName) async {
    try {
      final credential = await auth.createUserWithEmailAndPassword(
          email: email ?? "", password: password ?? "");

      if (credential.user != null) {
        if (fullName != null) {
          credential.user?.updateDisplayName(fullName);
        }
        credential.user?.sendEmailVerification();
      }
    } on FirebaseAuthException catch (e) {
      if (e.code == 'email-already-in-use') {
        print('An account already exists for that email.');
        if (!Platform.environment.containsKey('FLUTTER_TEST')) {
          showToast(
              "An account already exists for that email.", ToastType.ERROR,

Notice how each function takes in a dynamic auth which will either be our mocked firebase auth class or the real one. The functions themselves are fairly straightforward. We pass in the parameters needed to initiate the auth function, if it fails we parse the error code thats we get.

These are a couple of scenarios that we can test with the above config. Due note that you may have to install a few packages listed at the top of this code block in order to get the tests to work. The magic happens in the setup() block which is ran before we start the tests. We create a fake firebase auth user and then use it with all of our functions that we want to call in the test block

void main() {
  group("Authentication", () {
    late MaterialApp app;
    late MockUser user;
    late MockFirebaseAuth auth;

    setUp(() {
      user = MockUser(
        isAnonymous: false,
        uid: 'tester',
        email: 'test@example.com',
        displayName: 'Test',
      );
      auth = MockFirebaseAuth(signedIn: false, mockUser: user);
      app = MaterialApp(
          home: SignInScreen(primaryText: "Welcome", secondaryText: "Back"));
    });

    test("Can sign up with email and password", () {
      SignInScreen signIn = SignInScreen();
      signIn.signUpWithEmail(auth, user.email, "abcd_1234", user.displayName);
      expect(auth.currentUser?.email, user.email);
    });

    test("Can sign in as dev", () {
      SignInScreen signIn = SignInScreen();
      signIn.signInAsDev(auth, true);
      expect(auth.currentUser?.email, user.email);
    });

    test("Catches sign up email in use exception", () async {
      auth = MockFirebaseAuth(signedIn: false, mockUser: user);
      SignInScreen signIn = SignInScreen();

      whenCalling(Invocation.method(#createUserWithEmailAndPassword, null))
          .on(auth)
          .thenThrow(FirebaseAuthException(code: 'email-already-in-use'));
      expect(
        () => auth.createUserWithEmailAndPassword(
            email: user.email ?? "", password: ''),
        throwsA(isA<FirebaseAuthException>()),
      );
      await signIn.signUpWithEmail(
          auth, user.email, "abcd_1234", user.displayName);
      expect(auth.currentUser, null);
    });

    test("Can sign in with email and password", () {
      SignInScreen signIn = SignInScreen();
      signIn.signInWithEmailPassword(auth, user.email, "abcd_1234");
      expect(auth.currentUser, user);
    });

    test("Can fake google sign in", () {
      SignInScreen signIn = SignInScreen();
      whenCalling(Invocation.method(#signInWithGoogle, null))
          .on(auth)
          .thenThrow(
              Exception("Failed to open redirect for sign in with google"));

      signIn.signInWithGoogle();
    });

    test("Sign in user not found exception", () {
      SignInScreen signIn = SignInScreen();
      whenCalling(Invocation.method(#signInWithEmailAndPassword, null))
          .on(auth)
          .thenThrow(FirebaseAuthException(code: 'user-not-found'));
      expect(
        () => auth.signInWithEmailAndPassword(
            email: user.email ?? "", password: ""),
        throwsA(isA<FirebaseAuthException>()),
      );

      signIn.signInWithEmailPassword(auth, user.email, "abcd_1234");
      expect(auth.currentUser, null);
    });

    test("Sign in wrong password exception", () {
      SignInScreen signIn = SignInScreen();
      whenCalling(Invocation.method(#signInWithEmailAndPassword, null))
          .on(auth)
          .thenThrow(FirebaseAuthException(code: 'wrong-password'));
      expect(
        () => auth.signInWithEmailAndPassword(
            email: user.email ?? "", password: ""),
        throwsA(isA<FirebaseAuthException>()),
      );

      signIn.signInWithEmailPassword(auth, user.email, "abcd_1234");
      expect(auth.currentUser, null);
    });
Buy Me A CoffeeDigitalOcean Referral Badge
Loading...
Edward Beazer

Edward Beazer - I just like to build shit. Sometimes I get stuck for hours, even days while trying to figure out how to solve an issue or implement a new feature. Hope my tips and tutorials can save you some time.

DigitalOcean Referral Badge