Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non Default Ports Do Not work #11

Open
b0ot opened this issue Nov 21, 2020 · 11 comments
Open

Non Default Ports Do Not work #11

b0ot opened this issue Nov 21, 2020 · 11 comments

Comments

@b0ot
Copy link

b0ot commented Nov 21, 2020

@samtstern @yuchenshi @rachelmyers

I know this is a bug report and I shouldn't let my frustrations bleed through, but after spending weeks trying to get a WSL fix only to be forced to downgrade to WSL 1, I was pretty frustrated that I encountered another error so quickly. It has been weeks and countless hours trying to make it through a simple codelab.

Platform: Windows Build 19042.630 w/ WSL Version 1 Ubuntu 20.04
References:
Initially I came across this issue while trying to follow Todd/Rachel's Youtube Video on Unit Security Testing
Issue 61

Description:
I did a clean setup for the emulators code lab and followed the instructions to step 8.
The only change that I had to make is that my default ports are not free, so I had to modify the firebase.json file before running the emulators

{
  "firestore": {
    "rules": "firestore.rules",
    "indexes": "firestore.indexes.json"
  },
  "functions": {
    "source": "functions"
  },
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ]
  },
  "emulators": {
    "functions": {
      "port": 5002
    },
    "firestore": {
      "port": 8085
    },
    "hosting": {
      "port": 5007
    }
  }
}

During step 8 when I go to run the mocha tests I get the following error:

Error: Timeout of 5000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.

Based on my experimenting on my referenced issue, I believe that the mocha test doesn't know how to connect to the emulator on non-default ports. I had a work around for initializeTestApp, but could not find a workaround for initializeAdminApp.

@samtstern
Copy link
Contributor

@b00t you've run into a lot of bugs and issues trying to use Firebase, so your frustration is 100% warranted. Thank you for continuing to file feedback.

The firebase.json file is only used by the Firebase CLI. Any other libraries which interact with the emulators, such as @firebase/rules-unit-testing or firebase-admin find the emulators through the FIREBASE_<FOO>_EMULATOR_HOST environment variables not through the firebase.json file.

You can either set these yourself, or you can run your tests through firebase emulators:exec 'npm run test' which will automatically set the right environment variables.

I will see if I can improve the error messages in this case so that future users don't get stuck.

@samtstern samtstern self-assigned this Nov 23, 2020
@rachelmyers
Copy link
Contributor

Just to echo @samtstern, this is great feedback; thanks.

@samtstern
Copy link
Contributor

Looks like we already have warnings in the library:
https://github.com/firebase/firebase-js-sdk/blob/master/packages/rules-unit-testing/src/api/index.ts#L216

Did you see anything in your logs like:

Warning: FIRESTORE_EMULATOR_HOST not set, using default value localhost:8080

If not, maybe mocha is hiding those logs?

@b0ot
Copy link
Author

b0ot commented Nov 23, 2020

@rachelmyers Thanks.

@samtstern You are correct in that error appearing. The issue is I couldn't find any documentation on how to set the value. I also asked on other unofficial support channels (e.g. Slack) and searched r/firebase as well as stackoverflow. Given I'm very new to web programming so likely didn't understand the documentation properly.

When trying to follow Rachel and Todd's video on unit security rules ( Issue 61 ) eventually I was able to figure out a way to modify the function Todd wrote to change the port being used

const EMULATOR_PORT = 8086

function getFirestore(auth) {
  const db = firebase.initializeTestApp({projectId: MY_PROJECT_ID, auth: myAuth }).firestore();
  db.useEmulator("localhost", EMULATOR_PORT)
  return db
}

This seemed to work for this use case although I still got the error with
Warning: FIRESTORE_EMULATOR_HOST not set, using default value localhost:8080

The issue was that useEmulator does not work for the Admin SDK

function getAdminFirestore() {
  const db = firebase.initializeAdminApp({projectId: MY_PROJECT_ID }).firestore();
  db.useEmulator("localhost", EMULATOR_PORT)
  return db
}

As you would get the error: ERROR: TypeError: db.useEmulator is not a function

Note, I probably tried things that seem ridiculous to use based on the documentation
I tried
Attempt 1:
const FIRESTORE_EMULATOR_HOST = "localhost:8085"

Attempt 2:
export FIRESTORE_EMULATOR_HOST = "localhost:8085"

Attempt 3:
const db = firebase.initializeAdminApp({projectId: MY_PROJECT_ID, FIRESTORE_EMULATOR_HOST: "localhost:8085").firestore();

However none of those methods seemed to work.

Based on the recent post from sam

The firebase.json file is only used by the Firebase CLI. Any other libraries which interact with the emulators, such as @firebase/rules-unit-testing or firebase-admin find the emulators through the FIREBASE__EMULATOR_HOST environment variables not through the firebase.json file.

You can either set these yourself, or you can run your tests through firebase emulators:exec 'npm run test' which will automatically set the right environment variables.

It looks like you may actually set the env variables outside of the code in the shell, however I have no idea how to set them or manage them.

One last final aside:
In the youtube video you may want to add a note about updating to
const firebase = require('@firebase/rules-unit-testing');
I had issues when I originally followed the const firebase = require('@firebase/testing')

@samtstern
Copy link
Contributor

@b0ot thanks for walking us through what you tried. It's really clear that we're making too many assumptions about what you and other web developers understand! We need to be much clearer.

Let me explain a bit:

FIRESTORE_EMULATOR_HOST is an environment variable. They are set in your terminal shell and can be accessed by programs you run from the command line, so they're popular in server environments. Using all caps and underscores is a convention for environment variables. Another common one you may run into is GOOGLE_APPLICATION_CREDENTIALS which all Google Cloud SDKs will use to locate credentials. Environment variables (env vars) are used to allow configuring server applications from the outside without requiring code changes.

Here's a super quick example of setting and using one:

$ MESSAGE="Hello world"
$ echo "$MESSAGE"
Hello world

So if you want to set one for your unit tests, you can just do it when you run the command:

FIRESTORE_EMULATOR_HOST=localhost:8088 npm run test

When you run firebase emulators:exec we set the environment for you before running your command.

@yuchenshi
Copy link
Member

yuchenshi commented Nov 23, 2020

Drive-by comment in case anyone want this: If you have to set it within your code in Node.js (which we don't recommend), process.env.FIRESTORE_EMULATOR_HOST = "localhost:8085"; is the way to go. Make sure that is above any calls to the SDKs.

@b0ot
Copy link
Author

b0ot commented Nov 23, 2020

@samtstern thanks for the quick reply and @yuchenshi for the additional information.

I was able to get it to run successfully by exporting the env variable in my shell (bash)!

I wasn't able to get it to work with firebase emulators:exec however from what I can determine it is because my emulators were setup in a parent folder above my test folder where mocha was installed.

I believe there is probably a way I could modify the package.json script files to make it work, but haven't figured it out currently.
Main folder doesn't know about mocha, test folder wasn't starting the emulators correctly. I may experiment a bit more, but for now I'm happy that I have a way to make it work.

Eventually I'll make it through this codelab ... after all it says I only have 33 minute remaining :)

@samtstern
Copy link
Contributor

@b0ot we seriously appreciate your patience and this thread has spawned a whole bunch of internal conversation about how we can make this easier and clearer. So your bad experience will at least help the next person!

@samtstern
Copy link
Contributor

We're fixing this issue with two new methods here:
firebase/firebase-js-sdk#4388

Once that is merged and released, we'll update the docs to recommend them.

@cdedreuille
Copy link

I was also very confused about how to set up the environment variable correctly. I just want to share my use case in case it helps anyone. I'm running an app on Nextjs and I'm fetching data on the server using the admin sdk. On Nextjs you set up local environments in a .env.local file. I tried to paste export FIRESTORE_EMULATOR_HOST="localhost:8080" on my terminal but what I understand is that it creates a temporary environment variable.

As mentioned here, for permanent setting, you need to understand where to put the “export” script. Where here means Bash Shell Startup Script like /etc/profile, ~/.bash_profile, ~/.bashrc. But frankly I never really understood that part.

So in my case, what I ended up doing is:

if (process.env.NEXT_PUBLIC_DB_HOST === 'localhost') {
  process.env.FIRESTORE_EMULATOR_HOST = 'localhost:8080';
}

@Justinohallo
Copy link

Justinohallo commented Jun 7, 2021

In my package.json I used the following and it works:

"test": " FIRESTORE_EMULATOR_HOST=localhost:8088 FIREBASE_DATABASE_EMULATOR_HOST=localhost:9000 jest --watchAll --detectOpenHandles"

@samtstern samtstern removed their assignment Jul 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants