I am currently using FirebaseAuth for handling users for a Flutter app that only allows logging in through a phone number. Unfortunately I am facing an issue with Firebase Auth while running an integration test.
It works perfectly fine when using the application normally through an AVD or a real device, in dev and prod mode. However, when running the app in an integration test on a virtual device through the integration_test
package, the callbacks defined in FirebaseAuth.instance.verifyPhoneNumber()
are never fired, so the app gets stuck. It seems that the package never even sends a request to create the user or log in. When an integration test is running, the app uses an Auth Emulator through useAuthEmulator()
instead of connecting to the real dev project. I also tried connecting to our real project directly and I got the same issue. In both scenarios FirebaseAuth worked correctly when using the app normally, but stopped working when running the integration test.
The logs show no error that could give a clue as to what’s going on. There is no exception being raised, either.
Here’s how the function is used :
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: phoneNumber,
verificationCompleted: (credential) {
_logger.info("verificationCompleted called");
verificationCompleted(credential);
},
verificationFailed: (exception) {
_logger.info("verificationFailed called");
verificationFailed(exception);
},
codeSent: (verificationId, forceResendingToken) {
_logger.info("codeSent called");
codeSent(verificationId, forceResendingToken);
},
codeAutoRetrievalTimeout: (verificationId) {
_logger.info("codeAutoRetrievalTimeout called");
},
);
The app is initialized like so :
_logger.info("initialize called");
await Firebase.initializeApp(options: firebaseOptions);
if (integration) {
final emulatorPort = int.tryParse(const String.fromEnvironment(
"EMULATOR_PORT",
defaultValue: "9099",
)) ?? 9099;
await FirebaseAuth.instance.useAuthEmulator('10.0.2.2', emulatorPort);
}
await FirebaseAppCheck.instance.activate();
integration
is set to true when running the integration test. Since everything works outside of integration tests, I am quite stumped. What could cause this change in behavior only when running an integration test?
2
Answers
I found a solution after a lot of trial and error.
It seems that the issue was caused by two different things :
integration
argument I was talking about in the question wasn't passed around correctly, causing the app to not use the emulator when it was supposed to.pumpAndSettle
only waits for frame data to stop scheduling. Since during the request there was no frames scheduled, the pump method ended early and caused everything to stop before the backend had the time to do anything. I implemented a function that waits for a certainFinder
object to become available before continuing.TL;DR, it was simply user error.
Asynchronous Behavior in Tests:
You can use
tester.pump()
ortester.pumpAndSettle()
to wait for asynchronous operations to complete in Flutter integration tests.