Prototype Locally With Flutter and Firebase
Never mess up your online database again
As Flutter and Firebase use different languages (Dart and Node.js), testing/prototyping both together in a contained local environment is a non-trivial problem.
Note: Online testing is not preferable because it corrupts the database and requires a complicated setup (deploy and version matching).
We can achieve local testing with the Firebase Emulator Suite which is a mocked Firebase service.
The following diagram shows how Flutter apps interact with the Firebase Emulator Suite:
Let’s go through how to use Flutter with the Firebase Emulator suite step-by-step.
Note: The code used to illustrate in this post comes from my side-project. Although we mainly focus on Flutter with Firebase, with a few changes, it will apply to X + Firebase where X can be React Native, Cordova, etc.
Step 1: Install Firebase Emulator Suite
Firebase Emulator Suite comes with the Firebase CLI which can be installed with the following command:
npm install -g firebase-tools
Step 2: Bypass Authentication Step in Emulation
As shown in the diagram above, Firebase authentication is not part of the Firebase Emulator Suite. Consequently, data authentication/authorization won’t work locally, so they have to be mocked.
There are many ways to mock authentication. I used the environment variable set by the Firebase Emulator Suite to mock:
Step 3: Connect the Flutter App to Firebase Emulator Suite
We want to connect Firebase Cloud function callables to localhost:
Note: We want to use a top-level environment to control the local vs. cloud. There are many ways to achieve this. For example, setting an environment variable or using different entry points.
Here is an example of using different entry points:
Step 4: Enable HTTP (No “S”) Connection (iOS Only)
iOS doesn’t allow any HTTP requests by default.
To allow HTTP connections to localhost only, add the following snippet into
Step 5: Start Tests Locally
Running the following command in your Firebase project directory will start the tests:
npm run build &&
firebase emulators:exec --only functions,firestore \"cd ../../flutter_app && flutter drive --target=test_driver/emulator.dart\""
firebase emulator:exectakes a second argument as the command to execute on top of starting the emulator. In our case, that is
cd ../../flutter_app && flutter drive --target=test_driver/emulator.dart, meaning we want to first navigate to Flutter and start our integration tests.
npm run buildis important here because the emulator takes transpiled code only.
- It’s also a good idea to add the script into your
npm run hermetic-device-testso that you won’t have to remember such a long command.
- Alternatively, you can run the Emulator and Flutter apps separately for interactive debugging/development with
firebase emulators:exec --only functions,firestorein one terminal and
flutter runin another.
Step 6: Have a Cup of Coffee
The tests will look like this (refer to image caption for each execution stage):
Now you never have to worry about apps in development messing up the database again. Happy hacking with Flutter and Firebase.