Reputation: 59456
I am writing a Flutter app that has fairly complex logic over the Firebase Firestore documents.
I am trying to write unit tests using flutter_test
that actually execute this logic against the database (I know this is technically an integration test). This is because this logic has a lot of edge-cases I can only be sure are working if tested against the real database.
This seems to be an impossible task.
The 2. firebase package for Dart VM has this example:
import 'package:firebase/firebase_io.dart';
void main() {
var credential = ... // Retrieve auth credential
var fbClient = new FirebaseClient(credential); // FirebaseClient.anonymous() is also available
var path = ... // Full path to your database location with .json appended
// GET
var response = await fbClient.get(path);
// DELETE
await fbClient.delete(path);
...
}
... however it does not show how to get the credential
. The googleapis package shows how to get the credentials
:
final _credentials = new ServiceAccountCredentials.fromJson(r'''
{
"private_key_id": ...,
"private_key": ...,
"client_email": ...,
"client_id": ...,
"type": "service_account"
}
''');
... however this object is not a string and it is not written anywhere how to transform this into what the FirebaseClient
class expects (toString()
does not work). There is a Github issue on the firebase package on how to get this credentials but it is still unanswered.
I find it hard to believe that there is no information available online, that I could find, on how to write proper integration tests for Firebase Firestore.
Considerations:
Flutter Driver
because the tests are installed like normal apps in the phone and that takes time during development and it is not as straight-forward to debug as regular unit tests. Android Studio has very good test debug tools.How should I write integration tests that access Firebase Firestore?
Upvotes: 5
Views: 661
Reputation: 24197
Adding the scope below allowed me to access firebase realtime
'https://www.googleapis.com/auth/userinfo.email'
According to https://developers.google.com/identity/protocols/oauth2/scopes it says that that scope is allowed to 'View your email address'. This doesn't seem quite right but it made it work.
(if anyone can help me understand this please add to the answer).
Upvotes: 0
Reputation: 98
For others who were brought here, as I was a few hours ago, by a search for ways to create that mysterious credential
object when using the dart VM with Firebase, the following is my solution which works for accessing Firestore, at least.
The work is done by the Credentials class: (implemented below)
import 'package:firebase/firebase_io.dart';
String credential = await Credentials.fetch();
FirebaseClient fbClient = new FirebaseClient(credential);
The Credentials class creates the credential, using data from the Firebase Service Account private key (Firebase Console > [Project] > Settings > Project Settings > Service Accounts, then download the private key).
import 'dart:io';
import 'dart:convert';
import "package:googleapis_auth/auth_io.dart";
import 'package:http/http.dart' as http;
class Credentials {
/// Returns a credential string to be used in the constructor
/// of [FirebaseClient].
static Future<String> fetch() async {
Map<String, dynamic> pk = await getPrivateKey();
// Fields from Firebase private key
var accountCredentials = ServiceAccountCredentials.fromJson({
"private_key_id": pk['private_key_id'],
"private_key": pk['private_key'],
"client_email": pk['client_email'],
"client_id": pk['client_id'],
"type": "service_account",
});
// Define the required scopes.
// see https://firebase.google.com/docs/firestore/use-rest-api#working_with_google_identity_oauth_20_tokens
var scopes = [
"https://www.googleapis.com/auth/datastore",
];
var client = new http.Client();
AccessCredentials credentials =
await obtainAccessCredentialsViaServiceAccount(
accountCredentials, scopes, client);
client.close();
return credentials.accessToken.data;
}
static Future<Map<String, dynamic>> getPrivateKey() async {
String jsonString =
await File('/Path/to/firebase_private_key/keyfile.json')
.readAsString();
return json.decode(jsonString);
}
}
Upvotes: 4