firebase-tools:
Platform:
<script>
document.addEventListener("DOMContentLoaded", function () {
// this doesnt work
var firebaseConfig = {
authDomain: "localhost:5000",
projectId: "project-name-test"
};
// Initialize Firebase
const app = firebase.initializeApp(firebaseConfig);
// this works great
firebase.firestore().settings({
host: "localhost:5002",
ssl: false
})
</script>
It would be great to init the app with a custom projectId so that the projectId used in Tests against the emulator can be used in some test html / js interface stuff. I would like to keep all my tests and code using a different projectId just to prevent the issue of someone accidentally running them against the live system. Yes the firestore.rules should prevent any major issues but its still possible one of our developers could use their credentials and bearer token against a live url without realising.
I get "Your API key is invalid, please check you have copied it correctly"
Maybe theres a way to do this already and I just don't understand. The documentation for all this advanced usage of the local emulator is a little lacking. I spent all day trying to figure out why my GET requests to the emulator were not working:
Locally with emulator:
GET http://localhost:8080/emulator/v1/projects/example-project/databases/(default)/documents/user/alice
Doesnt work.
Response:
Not Found
Only to realise its because the /emulator/ part is only required when you call:
DELETE http://localhost:8080/emulator/v1/projects/example-project/databases/(default)/documents
To clear all documents.
It would be awesome if you could include an example project with tests that also sets up a sane local test environment for everything from auth, cloud functions and firestore calls. :)
This issue does not have all the information required by the template. Looks like you forgot to fill out some sections. Please update the issue with more information.
@madhavajay thanks for the feedback! I'm not 100% clear on your issue but I think this quickstart gives you the example you're looking for:
https://github.com/firebase/quickstart-nodejs/tree/master/firestore-emulator/browser-quickstart
Right now the only services we emulate are Firestore, Realtime Database, Cloud Functions, Hosting, and Pub/Sub. The big omission there is Authentication, so that's why something like authDomain: "localhost:5000" does not work. We are definitely trying to fix that though!
Let me know if that helps.
So I guess whats happening is the auto injected init.js file handles the config with your real project and allows you to auth against that which is really cool by the way. The problem is there is no way I can see to change your "projectId" in the JS which means that even though you can point your code to the local firestore emulator all your commands will be partitioned into the live projectId name space like:
http://localhost:5002/v1/projects/REAL-PROJECT-ID/databases/(default)/documents/user/alice
Where as with @firebase/testing you can do:
const app = await firebase.initializeTestApp({
projectId,
auth
})
This means all the tests can be written against a non real projectId.
My main concern is that with REAL auth occurring against the real project ID, it's totally possible that a developer could run a test command via the JS SDK against the live API by accident, in the case of the local emulator not being set correctly like:
firebase.firestore().settings({
host: "localhost:5002",
ssl: false
})
If the projectId could be set locally for use against the local emulator that would solve the issue. I know that a custom initializeApp can be run instead of init.js but its not clear what options to set for local and I get "Your API key is invalid, please check you have copied it correctly" when I try.
Perhaps it's not even possible currently.
firebase.initializeApp({
apiKey: "AIza....", // Auth / General Use
authDomain: "YOUR_APP.firebaseapp.com", // Auth with popup/redirect
databaseURL: "https://YOUR_APP.firebaseio.com", // Realtime Database
storageBucket: "YOUR_APP.appspot.com", // Storage
messagingSenderId: "123456789" // Cloud Messaging
});
I hope that explains what I mean a bit better. Local auth isn't really needed since a real JWT with userId can be used for user specific permissions testing and then "owner" can be used via the REST API for admin style operations. Or does that no longer work if the local projectId is different from the live JWT auth... my guess is its a little complicated!?
@madhavajay thanks for explaining all that.
So if you want to change the projectId with the automatic init scripts, just use the --project flag like this. For example using my project fir-dumpster:
$ firebase --project=fir-dumpster emulators:start
When I curl the init file I get something like this:
$ curl http://localhost:5000/__/firebase/init.js
if (typeof firebase === 'undefined') throw new Error('hosting/init-error: Firebase SDK not detected. You must include it before /__/firebase/init.js');
var firebaseConfig = {
"projectId": "fir-dumpster",
"databaseURL": "https://fir-dumpster.firebaseio.com",
"storageBucket": "fir-dumpster.appspot.com",
"locationId": "us-central",
"apiKey": "AIzaSyD3Vh...CPx7vJ20i_KjBPk",
"authDomain": "fir-dumpster.firebaseapp.com",
"messagingSenderId": "733...301"
};
if (firebaseConfig) {
firebase.initializeApp(firebaseConfig);
}
Now let's say I do this with a totally made up projectID like my-fake-project:
$ firebase --project=my-fake-project emulators:start --only hosting
i emulators: Starting emulators: hosting
✔ emulators: Emulator hub started at http://localhost:4000
âš hosting: Authentication error when trying to fetch your current web app configuration, have you run firebase login?
âš hosting: Could not fetch web app configuration and there is no cached configuration on this machine. Check your internet connection and make sure you are authenticated. To continue, you must call firebase.initializeApp({...}) in your code before using Firebase.
i hosting: Serving hosting files from: public
✔ hosting: Local server: http://localhost:5000
✔ hosting: Emulator started at http://localhost:5000
✔ All emulators started, it is now safe to connect.
You can see the emulators start up just fine but they warn me that they couldn't fetch a configuration for this project. That makes sense, it's not real!
When I curl the init script now I can see it doesn't do anything:
$ curl http://localhost:5000/__/firebase/init.js
if (typeof firebase === 'undefined') throw new Error('hosting/init-error: Firebase SDK not detected. You must include it before /__/firebase/init.js');
var firebaseConfig = undefined;
if (firebaseConfig) {
firebase.initializeApp(firebaseConfig);
}
So that leaves me to run initializeApp() on my own when my page loads. I don't need a messagingSenderId or even a storageBucket because none of those things are going to work on this fake project.
I think a good improvement would be for __init.js to automatically point your services at the emulator when possible. I will work on that.
Anyway I hope I have answered your questions! I am going to close this issue, but let me know if you have more and I am happy to discuss.
@samtstern thats really awesome. I knew there must be a way but was having trouble interrogating the dynamic config when using the --project param but didn't think to just hit the .js end point. Very smart. I agree this would be a great addition to the system to automatically handle the correct connections. Also is there a reason that we need to manually override things like this:
firebase.firestore().settings({
host: "localhost:8080",
ssl: false
})
firebase.functions().useFunctionsEmulator("http://localhost:5001")
Seems like it would make more sense to do this as part of the initializeApp config or as you mentioned automatically in __init.js.
@madhavajay yep you're totally right. I'm going to work on this in #1969 ... we can at least make this better through __init.js magic.