Reputation: 384
I want to test locally my firebase functions. These functions make firestore queries.
So i start the emulator firebase emulators:start
and in my client i use firebase.functions().useFunctionsEmulator('http://localhost:5001')
.
My functions work well when i call them in my client. I can read/write data inside the firestore emulator.
The problem :
I want to read the firestore emulator data directly inside my client, like :
firebase.firestore().collection('tests').get().then(tests => {
console.log( tests.docs.map(test=>test.map) )
})
but i can't find how to set the firestore emulator inside my client.
here what i tried:
1) Firestore setting
firebase.firestore().settings({
host:'http://localhost:8080',
ssl:false
})
result :
i get @firebase/firestore: Firestore (6.3.5): Could not reach Cloud Firestore backend. Backend didn't respond within 10 seconds.
inside my client console.
The http request returns 'Not found'
2) Set the emulator url inside my firebaseConfig
var firebaseConfig = {
// ...
databaseURL: "http://localhost:8080",
// ...
}
firebase.initializeApp(firebaseConfig)
in this case, the remote server (https://firestore.googleapis.com..) is requested.
So i want to setup one of these two cases :
1) Using the remote firestore inside my functions emulators
OR
2) Using the local firestore emulator inside my client code.
Anyone has already done this ?
Upvotes: 14
Views: 11569
Reputation: 166
Define the FIRESTORE_EMULATOR_HOST environment variable
If you are using a library that supports the FIRESTORE_EMULATOR_HOST environment variable, run:
export FIRESTORE_EMULATOR_HOST=localhost:8080
or just add FIRESTORE_EMULATOR_HOST=localhost:8080 to your .env file
Upvotes: 0
Reputation: 6244
Okay, this is trivial... In your firestore cient config you should have provided the host, not the origin for firestore (the protocol is set using the ssl
parameter):
firebase.firestore().settings({
host: 'localhost:8080',
ssl: false
})
At least this solved it for me when I had the exact same error.
Just FYI to anyone who's reading this - if you run into problems with the firestore client, you can use debug
level logging, just set firebase.firestore.setLogLevel('debug')
. Had the OP done that, he might have noticed that firebase is accessing firestore at http://http://localhost:8080/
...
Upvotes: 2
Reputation: 10873
npm i -D @firebase/testing
firebase setup:emulators:firestore
firebase serve --only firestore
const firebase = require("@firebase/testing");
// Helper function to setup test db
function authedApp(auth) {
return firebase
.initializeTestApp({ projectId: FIRESTORE_PROJECT_ID, auth })
.firestore();
}
// Setup methods
beforeEach(async () => {
// Clear the database between tests
await firebase.clearFirestoreData({ projectId: FIRESTORE_PROJECT_ID });
});
// Clean up apps between tests.
afterEach(async () => {
await Promise.all(firebase.apps().map(app => app.delete()));
});
it("should retrieve correct item", async () => {
// Init test db
const db = authedApp(null);
// Manually add item to collection
const ref = await db.collection(COLLECTION_NAME).add({name: 'test item'});
// Fetch item by id
const resp = await db.collection(COLLECTION_NAME).doc(ref.id).get();
// test the output
expect(resp).toBeDefined();
expect(resp).toEqual(expect.objectContaining({name: 'test item'}));
});
Of course your particular setup and circumstances will differ, but this at least should give you a general idea. More info: https://firebase.google.com/docs/rules/unit-tests
Note from 'Test your Cloud Firestore Security Rules'
Data written to the Cloud Firestore emulator is held in memory until the emulator is stopped. If the emulator is run continuously, this may have an impact on test isolation. To ensure that data written in one test is not read in another, either explicitly clear your data with
clearFirestoreData
, or assign a different project ID for each independent test: when you call firebase.initializeAdminApp or firebase.initializeTestApp, append a user ID, timestamp, or random integer to the projectID.
Edit: I wrote a blog post a while back, which goes into more detail about the subject.
Upvotes: 11
Reputation: 384
Ok i found how to do it :
1) launch the functions emulator locally:
set GOOGLE_APPLICATION_CREDENTIALS=./privatekey.json && firebase serve --only functions
2) then client side:
if (process.env.NODE_ENV === 'development') {
firebase.functions().useFunctionsEmulator('http://localhost:5001')
}
Upvotes: 2
Reputation: 630
I had the same problem too. I found the following example, which looks like its still work in progress:
https://github.com/firebase/quickstart-nodejs/tree/master/firestore-emulator/browser-quickstart
They didn't use @firebase/testing
directly in their example. When I did try to embed @firebase/testing
in my webpack code, it tries to connect via grpc
, which attempts to do fs.existsSync
, which doesn't exist in webpack
browser context. They prefer to enable the functionality via WebChannel instead.
Some caveats as of Nov 2019:
@firebase/firestore: Firestore (6.3.5): Could not reach Cloud Firestore backend. Backend didn't respond within 10 seconds.
Despite having those errors, my functions were still able to connect to the local firestore.
Versions I had at time I was testing:
Update 11/18:
quickstart-nodejs
github and it seems I just needed to use the latest versions of everything. Versions:
Upvotes: 2