prescottprue / cypress-firebase

Cypress plugin and custom commands for testing Firebase projects
MIT License
273 stars 50 forks source link

GCLOUD_PROJECT error #124

Closed Buuntu closed 4 years ago

Buuntu commented 4 years ago

I get the following when following the README instructions and starting cypress:

**Message:** The function exported by the plugins file threw an error.

**Details:** Error: Error GCLOUD_PROJECT environment variable or project_id from service account to initialize Firebase.

Any ideas?

prescottprue commented 4 years ago

Did you try adding your service account to the ./serviceAccount.json file as described in the setup? If you are just running against emulators instead of full instance, you can also just pass the GCLOUD_PROJECT environment variable as described in the error.

Buuntu commented 4 years ago

Yeah, I have the serviceAccount.json at the root directory (outside of cypress folder) and also have tried hardcoding those settings into the config variable in cypress/support/commands.js. I tried setting GLOUD_PROJECT and FIREBASE_PROJECT_ID in cypress.env.json as well.

prescottprue commented 4 years ago

Hmmm... Environment variables in the plugin are being loaded from the node environment instead of using the Cypress environment (cypress.env.json). That said, the service account should be getting loaded regardless

Did you try setting an env variable inline as part of your command like so:

"test:open": "GCLOUD_PROJECT=some-project cypress open",

or if you are using cross-env:

"test:open": "cross-env GCLOUD_PROJECT=some-project cypress open",

If that doesn't work, are you able to provide the repo where you are experiencing the issue so that I can try to reproduce?

Buuntu commented 4 years ago

I see. So when I do that I get a different error:

cypress-firebase: Error initializing firebase-admin instance: Service account object must contain a string "private_key" property.

it's like my service account properties are not getting read anywhere? Which is confusing because I have them hardcoded like so in cypress/support/commands.js:

import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/database';
import 'firebase/firestore';
import { attachCustomCommands } from 'cypress-firebase';
// const firebaseConfig = require('serviceAccount.json');

const firebaseConfig = {
  // secret keys are set here
};

// window.fbInstance = firebase.initializeApp(firebaseConfig);

firebase.initializeApp(firebaseConfig);

attachCustomCommands({ Cypress, cy, firebase });

and my cypress/plugins/index.js file:

const admin = require('firebase-admin');
const cypressFirebasePlugin = require('cypress-firebase').plugin;

module.exports = (on, config) => {
  return cypressFirebasePlugin(on, config, admin);
};

cypress/support/index.js:

import './commands';
prescottprue commented 4 years ago

Firebase config is different than your service account - firebaseConfig is the front end config for Firebase's client JS SDK used in the browser - NOT firebase-admin which is used in the node context (i.e. plugins). Requiring the serviceAccount in front end logic like the commands file will not work as you currently have it. The firebase-admin instance is initialized using the service account within cypress-firebase.

You are right that it seems that the serviceAccount is not being picked up - you confirmed that is in the root of your project and not in the cypress folder? Is you service account maybe using the camel case notation instead? I.e projectId, privateKey etc instead of project_id, private_key etc

Buuntu commented 4 years ago

Oh... thanks for the clarification - I think that's the issue then. I thought the frontend config was sufficient. I copied the full serviceAccount.json from firebase and now it works. Why does this need firebase-admin to do login and not just firebase-sdk?

Essentially I am trying to mock out frontend login/user creation with cypress so I can test a registration form I have, so maybe I will need a different approach. All my backend does is verify the firebase token, the user creation/login all happens from the firebase JS SDK.

prescottprue commented 4 years ago

firebase-admin is used for generating authentication tokens which the JS SDK then uses to login. firebase-admin is interacting with the database with administrative rights for reading/writing when seeding/verifying data.

Usually for tests that are not testing login, you would login with cy.login which uses a custom token generated by firebase-admin so that the user is logged in without needing to go through the login flow (common pattern with Cypress). As for what you are trying to achieve with testing log in, you can login manually in the UI then use cy.callFirestore or cy.callRtdb to verify that data is written to the database as you expect on login

Buuntu commented 4 years ago

firebase-admin is used for generating authentication tokens which the JS SDK then uses to login. firebase-admin is interacting with the database with administrative rights for reading/writing when seeding/verifying data.

Usually for tests that are not testing login, you would login with cy.login which uses a custom token generated by firebase-admin so that the user is logged in without needing to go through the login flow (common pattern with Cypress). As for what you are trying to achieve with testing log in, you can login manually in the UI then use cy.callFirestore or cy.callRtdb to verify that data is written to the database as you expect on login

Okay thanks!

Do you think to test user creation it would be better to mock firebase.auth().createUserWithEmailAndPassword with sinon stubs? I don't want to create a new user each time.

prescottprue commented 4 years ago

@Buuntu Yeah that would be smart - there is not currently an emulator for auth in Firebase, so it would create the user every time like you are mentioning. You could also mock the responses from the Google API though cypress, but that will most likely be a bit more complicated since there are multiple call, and that could also change - where with the mocking method you only have that issue if the JS API changes (usually only happens in major version changes).

Going to close this issue for now since you seem to be squared away