prescottprue/cypress-firebase

ApiKey Error When using Github Actions and Cypress

isab opened this issue · 11 comments

isab commented

Describe the bug

I am getting this error when my Cypress test suite runs on Github Actions

Your API key is invalid, please check you have copied it correctly.

This error only happens in the Github Actions environment and does NOT happen when I run Cypress locally.

To Reproduce
It's in a private repo so I can't reproduce it for you specifically. But here is how I run the scripts.

Locally in development:
cypress open to start cypress and run the tests
yarn dev to start my localhost:3000 server for the cypress tests

Github Actions Script:

name: End-to-end tests

on: [push]

jobs:
  cypress-run:
    runs-on: ubuntu-latest
    container: cypress/browsers:node12.18.3-chrome87-ff82
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Cypress run
        uses: cypress-io/github-action@v2
        with:
          build: yarn build
          start: yarn dev
          wait-on: 'http://localhost:3000'
          wait-on-timeout: 120
          browser: chrome
          record: true
        env:
          CI_FB_SECRETS: ${{ secrets.CYPRESS_FB_SECRETS }}
          CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_KEY }}
          CYPRESS_TEST_UID: ${{ secrets.CYPRESS_UID }}
          SERVICE_ACCOUNT: ${{ secrets.CYPRESS_SERVICE_ACCOUNT }}
          GITHUB_HEAD_REF: ${{ github.head_ref }}
          GITHUB_REF: ${{ github.ref }}

Expected behavior/code
The tests should not have the ApiKey error in the Github Actions environment.

Additional Context/Screenshots

Things I've already tried and debugged:

  • I have quadruple checked the ApiKeys and they match. I checked all the service account secrets and app secrets from both the Cypress server and my own app server and they all match.
  • yarn build and yarn dev build the app and start the localhost server without any errors.
  • I've added all the secrets to Github as well and double checked those.

Context:

  • I don't run my test suite in a Firebase Emulator. Should I be doing that?

Here's my code:

// plugins/index.js
const admin = require('firebase-admin');
const cypressFirebasePlugin = require('cypress-firebase').plugin;

const creds = JSON.parse(process.env.SERVICE_ACCOUNT);

module.exports = (on, config) => {
  admin.initializeApp({
    credential: admin.credential.cert(creds),
    databaseURL: 'https://apollo-sandbox-2f24e.firebaseio.com',
  });
  const extendedConfig = cypressFirebasePlugin(on, config, admin);

  return extendedConfig;
};
// support/commands.js
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/database';
import 'firebase/firestore';
import { attachCustomCommands } from 'cypress-firebase';

// replaced my secrets with `my app`
const config = {
  apiKey: 'my_key',
  authDomain: 'myapp.firebaseapp.com',
  projectId: 'myapp',
  storageBucket: 'myapp.appspot.com',
  messagingSenderId: '127620730504',
  appId: 'myappId',
  measurementId: 'G-NG3DF18JP4',
};
firebase.initializeApp(config);

attachCustomCommands({ Cypress, cy, firebase });

Any help would be appreciated! Happy to provide more context as well.

Can you share which version of cypress-firebase you are using? There was a bug discovered in v1.8.1 that was causing an issue with databaseURL - wondering if this is a similar issue

Also - was there a reason that you parse the SERVICE_ACCOUNT env var yourself? That should be handled internally, so you should be able to switch to the following:

// plugins/index.js
const admin = require('firebase-admin');
const cypressFirebasePlugin = require('cypress-firebase').plugin;

module.exports = (on, config) => {
  const extendedConfig = cypressFirebasePlugin(on, config, admin);

  return extendedConfig;
};

Also wanted to ask a few more questions:

  • What is CI_FB_SECRETS? Are you parse anything in the test env?
  • Are you intended to have the tests communicate with your real database or would you be open to using the database emulators?
  • Seems like the apiKey error may be coming from your app - are you able to confirm that value within the app itself (as opposed to in Cypress)

This repo called "firething" is a test repo created by generator-react-firebase which uses cypress-firebase in Github actions. For this project node-config is used to load the same config in the browser and cypress environments. Maybe that will be helpful as reference?

@prescottprue just as a reminder I was the one that recently discovered the bug with the databaseURL and ended up here when I faced my next issue.

Currently if I set only the databaseURL in the config I get the same error as OP but in this case its expected.
But if I actually fill out the config hard coded like OP in his last codeblock I get this

The following error originated from your test code, not from Cypress.

  > FIREBASE FATAL ERROR: Can't determine Firebase Database URL. Be sure to include  a Project ID when calling firebase.initializeApp(). 

@spnkdev Is that the case with the newest version? v1.9.1?

Can you all provide a link to the repo? I'm wondering if the issue is the config not loading the application itself if you are saying you are hardcoding the values support/commands.js. I say that because the admin initialization uses credential and databaseURL.

@prescottprue Actually just ignore my previous issue, I found the issue so its not a problem with the library.

For @isab 's problem, if the problems are local try to set the needed config env variables under plugin/index.js something like this:

.env
CYPRESS_TEST_UID=UIDHERE

plugin/index.js

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

//You can use the below plugin as well to load environment variables defined in your .env
const dotenvPlugin = require('cypress-dotenv');


module.exports = (on, config) => {

  config.env.TEST_UID = dotenvPlugin(config).env.TEST_UID;
//or 
  config.env.TEST_UID = process.env.TEST_UID;


  const extendedConfig = cypressFirebasePlugin(on, config, admin);

  // Add other plugins/tasks such as code coverage here

  return extendedConfig;
};
isab commented

@prescottprue @spnkdev Thanks for the suggestions.

I made the update and now my files look like this:

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

module.exports = (on, config) => {
  const extendedConfig = cypressFirebasePlugin(on, config, admin);

  return extendedConfig;
};
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/database';
import 'firebase/firestore';
import 'firebase/analytics';
import { attachCustomCommands } from 'cypress-firebase';

const config = {
  apiKey: '...',
  authDomain: 'apollo-sandbox-2f24e.firebaseapp.com',
  databaseURL: 'https://apollo-sandbox-2f24e.firebaseio.com',
  projectId: 'apollo-sandbox-2f24e',
  storageBucket: 'apollo-sandbox-2f24e.appspot.com',
};
firebase.initializeApp(config);

attachCustomCommands({ Cypress, cy, firebase });

I am still getting this error in Github Actions though:
> Your API key is invalid, please check you have copied it correctly.

I've followed the firething repo as well and no luck.

To answer your question @prescottprue :

  • What is CI_FB_SECRETS? Are you parse anything in the test env?
    This comes from Github Secrets and I parse it as JSON for my localhost environment that is also spinning up firebase since I need it for my integration tests.

  • Are you intended to have the tests communicate with your real database or would you be open to using the database emulators?
    Yes I intend to have it communicate with the real database since I need to verify values with my real database. Would an emulator fix my problem?

  • Seems like the apiKey error may be coming from your app - are you able to confirm that value within the app itself (as opposed to in Cypress)
    Yes I can confirm the apiKeys are matching and correct. I confirmed by console logging the values from the cypress and localhost environment.

I'm having the same issue. Has anyone had any luck with this?

@isab yes I personally have found the emulators to be much more stable for testing since you are not dealing with network latencies and you can have as many running in parallel as you want without them colliding (where a real database can have collisions if multiple copies of a single test are running within a short time of each other - or if you clear collections in setup or cleanup of tests)

I would be interested to hear if anyone is still experiencing this with v2 - the way that we initialize the admin instance changed slightly. If you are needing to pass a databaseURL that can be passed directly:

// plugins/index.js
const admin = require('firebase-admin');
const cypressFirebasePlugin = require('cypress-firebase').plugin;

module.exports = (on, config) => {
  const extendedConfig = cypressFirebasePlugin(on, config, admin, {
    databaseURL: 'https://apollo-sandbox-2f24e.firebaseio.com',
  });

  return extendedConfig;
};

@isab Is anyone still experiencing this issue? Trying to replicate on my end, but haven't been able to in a number of different projects

isab commented

@prescottprue I haven't been working on the related codebase for a while now so unfortunately don't have an answer for you. You can feel free to close it and if I encounter this again in the future I'll write a new issue. Thanks!

@isab Thanks for the response