Problem running JS file with firebase emulators: exec - node.js

I was trying out the new Firebase Emulators UI announced on May 21, 2020. In the Firebase Docs, I noticed that there is a CLI command that allows us to run a script file:
firebase emulators:exec scriptpath
Run the script at scriptpath after starting emulators for the
Firebase products configured in firebase.json. Emulator processes will
automatically stop when the script has finished running.
Although the docs does not mention what kind of script file it should be, I presume it could be either a test script or a workable JavaScript file that be executed standalone with node filename.js without any errors. This makes sense because I can actually run an initial JS file that pre-populate some test data to the Firestore Emulator for further testing.
But since I've previously started the emulators, I have to open a new instance of command window to run the firebase emulators:exec command. Unfortunately, I hit the following errors:
D:\Firebase\my-project>firebase emulators:exec setup-db.js
i emulators: Starting emulators: functions, firestore, database, hosting, pubsub
! hub: emulator hub unable to start on port 4400, starting on 4401 instead.
! emulators: It seems that you are running multiple instances of the emulator suite for project my-project-id. This may result in unexpected behavior.
i emulators: Shutting down emulators.
i hub: Stopping emulator hub
! functions: Port 5001 is not open on localhost, could not start Functions Emulator.
! functions: To select a different host/port, specify that host/port in a firebase.json config file:
{
// ...
"emulators": {
"functions": {
"host": "HOST",
"port": "PORT"
}
}
}
i emulators: Shutting down emulators.
Error: Could not start Functions Emulator, port taken.
Take note of this line:
! emulators: It seems that you are running multiple instances of the emulator suite for project my-project-id. This may result in unexpected behavior.
So, how can I run the firebase emulators:exec AFTER the emulators start as mentioned in the Firebase Docs and, can I run the JS file for the said purpose? Thanks in advance!
UPDATE:
If I run just the firebase emulators:exec setup-imtp-db.js without prior running the firebase emulators:start command, I ran into the following errors:
Note that the setup-imtp-db.js does not contain any Cloud Functions code but just a standalone JS file that populates data from another JSON file into Firestore via Admin SDK. I'm using Node.js 12.14.0 and firebase-tools 8.4.0.

According to Firebase CLI Github README.md:
emulators:exec Start the local Firebase emulators, run a test
script, then shut down the emulators.
So the scriptpath parameter isn't really meant to run a JavaScript file that pre-populates data on Firestore Emulator (and presents on its Emulator UI) for the purpose of UI Functional Test or Integrated Test. The emulators:exec will immediately shut down the emulators after finish executing the test script.
As #Doug Stevenson suggested in the comment, if a proper error handling is expected from the emulators or a new feature is required, a request or bug report can be posted on Github for firebase-tools.

While the emulators:exec command is clearly not meant for seeding a database while continuing (manual) testing, as explained in the accepted answer, I did accomplish something of the kind.
I successfully prevented my emulators:exec-invoked database seeding script from exiting with the following method:
// db-seeder.js
const admin = require('firebase-admin');
const app = admin.initializeApp({
projectId: 'demo-test'
});
const db = admin.firestore(app);
...
// Prevents the seed Node.js process from exiting,
// which in turn prevents the emulators from exiting.
process.stdin.resume();
Along with the --ui switch, this gives an experience comparable to running emulators:start, but then with a seeded database:
firebase --project demo-test emulators:exec --ui db-seeder.js
I had to use this method because I was getting credential problems when trying to seed the database with a standalone script, see details here on dev.to.

Related

Error: Could not load the default credentials in emulators using firebase emulators:exec

I'm trying to test my functions using the emulator but I've came across a problem with the command I'm using.
I'm using this command here:
firebase emulators:exec --project stormdevelopment-64ea9 --import ~/Documents/work/storm/backups/firestore/2023-01-15T10:30:05_94356 --token "<my-token>" "npm run testUnix ./tests/endPoints/auth.test.ts".
When I run the script I get this error in the console:
Error: Could not load the default credentials..
In the auth.test.ts script I'm initializing the credentials of the admin like this: admin.initializeApp();. In my functions I'm using the
import * as adminImported from "firebase-admin";
export const admin = adminImported.initializeApp();
The problem seems to be in the backend and not in the test script because in the test script I've tried to create a user with the command:
await admin.auth().createUser({
email: userForThisTest.email,
password: userForThisTest.password,
});
and it works without a problem, so the user gets created correctly.
I've came across different possible solutions found online but everything I try doesn't work.

why process.env.FIRESTORE_EMULATOR_HOST will be undefined in test environment? even though I have run the emulator

I am using
Node 14
firebase functions-test: 0.2.3
firebase-admin: 9.6.0
firebase-functions: 3.13.2
firebase tools: 9.10.0
mocha: 8.3.2,
ts-node: 9.1.1
if I run firebase emulators:start
then I will expect process.env will have properties like
"FUNCTIONS_EMULATOR": "true",
"FIRESTORE_EMULATOR_HOST": "localhost:8080"
now I need to create testing for my cloud function using mocha, I will test it using Firestore and functions emulator, I give my file name events_cron_job.test.ts
after I run the simulator, I try to console log those values and I got undefined like this
I expect
console.log(process.env.FUNCTIONS_EMULATOR) // will be "true"
console.log(process.env.FIRESTORE_EMULATOR_HOST) // will be "localhost:8080"
I think this is only happen in test environment ( I am using mocha ), I have regular http triggers and it works as expected
before running the emulator, I try to execute this on terminal
export FIRESTORE_EMULATOR_HOST="localhost:8080"
export FUNCTIONS_EMULATOR="true"
and then execute firebase emulators:start , but the result will be the same, I still get undefined for those values
because those values are undefined, then if my laptop is disconnected from the internet, then this testing will not run ( i.e it will only access the data in production server, not the emulator! ), I expect the test will still run even if there is no internet connection since I use emulator.
I run the mocha test using
mocha -r ts-node/register src/tests/cloud_function_tests --recursive --extension .test.ts --timeout 60000 --exit
As you can see in this Github issue comment, in order to run tests with the Firebase emulator you should use the following command to trigger it:
firebase emulators:exec "npm test"
As this is how tests where intended to be executed by the Firebase Team using the emulator.

Prevent firebase emulator closing on finishing the tests

I am running my firebase tests using the following command
firebase emulators:exec --ui 'mocha --reporter spec --timeout 10000'
but the ui closes and emulators shut down as soon as the test finishes. I have looked at the params in the help but cant seem to find a way to keep them running so I can check values in the db.
I have tried starting the emulators first and then running with exec but it always complains that emulator instances are already running.
Is there a method of doing this?
You can try starting the firebase emulators:start and then running your test script after it has started
mocha --reporter spec --timeout 10000
It fails when you run exec after starting because the ports assigned to the emulators are busy.. Instead of running exec after the emulators have started, run the test script itself

Node.js - start a process (firebase emulators) and read its output

I want to start firebase emulators before Jest tests.
Execute this, but programatically:
E:\my-projct>firebase emulators:start --only firestore
i emulators: Starting emulators: firestore
i firestore: Serving ALL traffic (including WebChannel) on http://localhost:8080
! firestore: Support for WebChannel on a separate port (8081) is DEPRECATED and will go away soon. Please use port above instead.
i firestore: Emulator logging to firestore-debug.log
+ firestore: Emulator started at http://localhost:8080
i firestore: For testing set FIRESTORE_EMULATOR_HOST=localhost:8080
+ All emulators started, it is now safe to connect.
Therefore, I need to:
Execute the command
Wait for the "All emulators started" string to appear.
How do I read the output?
I have tried the following, all it prints is a newline.
const cp = require('child_process');
const child = cp.exec('firebase emulators:start --only firestore');
child.stdout.addListener('data', data => console.log(data.toString()));
This is exactly why we have made the firebase emulators:exec command.
So let's say you use "npm run test" to run your Jest scripts, you would use:
firebase emulators:exec "npm run test"
This will:
Start the emulators and wait till they're ready
Run your script (npm run test in this case)
Wait for your script to exit
Cleanly shut down the emulators

How to correct a Bluemix Node.js app that can't accept connections

I created a new Node.js app on Bluemix this morning and downloaded the boilerplate code. I worked on it locally and then pushed it up. On Bluemix, it refuses to start. The error according to the logs is:
Instance (index 0) failed to start accepting connections
So I Googled for that, in every case where I found the result, the answer was that my application was trying to use a specific port instead of letting Bluemix set it.
Ok, but I'm setting the host/port with the exact code the boilerplate uses:
var appEnv = cfenv.getAppEnv();
// start server on the specified port and binding host
app.listen(appEnv.port, function() {
// print a message when the server starts listening
console.log("server starting on " + appEnv.url);
});
So if this is incorrect, it means the code Bluemix told me to download itself is incorrect as well, and I can't imagine that is the issue.
To identify whether cfenv is at fault, I've tested that piece of code with a number of more complex Node.js apps I have, and they work perfectly on Bluemix.
That message can also come when an application you've deployed to Bluemix fails to start at all. Here's a few things you can do to troubleshoot your Node.js application on Bluemix.
Tail logs in another terminal while pushing with "cf logs
". Inspect logs after the failure to see if something
failed during the staging process.
Check that your start command in one of two recommended places, scripts.start in package.json or in a Procfile with web: node <start-script>.
Check that your application works locally. First (optional), create a .cfignore file with "/node_modules" in it, so that when you push the app to Bluemix, CF CLI doesn't push your entire folder of node_modules (as they will be installed dynamically). Next, wipe out your node_modules directory and do an npm install --production followed by npm start (or your custom start command). This is what Bluemix does when trying to start your application, so you should double check that it works locally.
Finally, try bumping up your memory, although this is very unlikely that this is why your application fails to start.

Resources