spencerlepine / woofer

Dating app for pets - a full stack MERN project. Complete with CI/CD pipeline w/ Jest, GitHub Actions, Docker Hub, and AWS EC2
https://youtu.be/aiJhCoZRc78
2 stars 1 forks source link

use Firebase Emulator #92

Closed spencerlepine closed 2 years ago

spencerlepine commented 2 years ago

use Firebase Emulator

This app connects to several Firebase (BaaS) services in production. This cloud service should not be used during development. With the Firebase Javascript SDK and the Firebase Emulator Suite, we can run everything locally.

With the emulator set up for local development, there is only one more step: using the Firebase Emulator in the GitHub Actions during testing.

Checklist


Research

package.json

{
  "name": "player-tiers",
  "private": true,
  "scripts": {
    "dev": "next dev -p 3020",
    "dev:emulator": "firebase emulators:exec 'npm run dev' --import=scripts/firebase/firestore-export/ --ui",
    "build": "next build",
    "build:emulator": "firebase emulators:exec 'npm run build' --import=scripts/firebase/firestore-export/",
    "start": "next start",
    "start:emulator": "firebase emulators:exec 'npm start' --import=scripts/firebase/firestore-export/"
  }
}

GitHub Actions example

name: CI

on: [push]
  # linting, type-checking, unit testing jobs

  e2e:
    name: End-to-end
    runs-on: ubuntu-latest
    container: cypress/included:7.0.1

    steps:
      - name: Checkout repo
        uses: actions/checkout@v2

      - name: Install npm dependencies
        run: npm ci

      # Setup Java for firebase CLI
      - name: Install Java
        uses: actions/setup-java@v2
        with:
          distribution: 'adopt'
          java-version: '11'

      # Run all Cypress tests in Chrome using firebase emulator
      - name: Cypress run
        uses: cypress-io/github-action@v2.9.7
        with:
          browser: chrome
          build: npm run build:emulator
          start: npm run start:emulator
        env:
          # Authorization for running the firebase CLI (emulator)
          FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}

          # Cypress variables
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          CYPRESS_BASE_URL: http://localhost:3021

          # Authorization for firebase-admin (server-side)
          FIREBASE_PROJECT_ID: player-tiers
          FIREBASE_PRIVATE_KEY:  ${{ secrets.FIREBASE_PRIVATE_KEY }}
          FIREBASE_CLIENT_EMAIL:  ${{ secrets.FIREBASE_CLIENT_EMAIL }}
          FIRESTORE_EMULATOR_HOST: localhost:8080

          # Authorization for firebase web API
          NEXT_PUBLIC_FIREBASE_PROJECT_ID: player-tiers
          NEXT_PUBLIC_FIREBASE_API_KEY: ${{ secrets.NEXT_PUBLIC_FIREBASE_API_KEY }}

Cache the Firebase emulator

jobs:
  test:
    runs-on: ubuntu-latest
    env: FIREBASE_EMULATORS_PATH: ${{ github.workspace }}/emulator-cache

    steps:
      - name: Cache firebase emulators
        uses: actions/cache@v2
        with:
          path: ${{ env.FIREBASE_EMULATORS_PATH }}
          key:
            ${{ runner.os }}-firebase-emulators-${{
            hashFiles('emulator-cache/**') }}
        continue-on-error: true

NodeJS Firestore mock

// create testenv for mocking changes
const testEnv = functions();

// First set up unique project id for these tests, so that any other test files run in parallel
// is not collapsing with this one.
const projectId = 'sample';

// initialize test database
process.env.GCLOUD_PROJECT = projectId;
process.env.FIRESTORE_EMULATOR_HOST = 'localhost:8080';
admin.initializeApp({ projectId });

const db = admin.firestore();

firebase.json

{
  "functions": {
    "predeploy": [
      "npm --prefix \"$RESOURCE_DIR\" run lint",
      "npm --prefix \"$RESOURCE_DIR\" run build"
    ],
    "source": "functions"
  },
  "emulators": {
    "firestore": {
      "port": 8080
    },
    "database": {
      "port": 9000
    },
    "ui": {
      "enabled": true
    }
  }
}