I'm developing a web site using Next.js hosted by Cloud Functions. It uses Firestore as main database. And some Firestore-Trigger functions exist.
Now, I wanted to test my functions and firestore.rules with Firestore Emulator. Due to manage its codes in GitHub, I wanted to use GitHub Actions for test.
I tried some ways to find more simple way to achive it. As a result of various investigations, I think preparing all-in-one GitHub Actions instance and using firebase emulators:exec
command is most simple way.
Here is how I setup auto testing system.
Setup local test
First of all, write tests and setup configurations to be able to run test in my local machine.
Here is what I committed.
https://github.com/yosan/tennico/pull/13/files
I'll explain some points in it.
Use firebase emulators:exec
Add this setting to package.json.
"scripts": {
"test": "firebase emulators:exec —only firestore 'jest --silent'"
},
firebase emulators:exec
is useful command. It downloads, launch, and stop Firebase Emulator automatically.
While executing tests, many Cloud Functions logs are shown on our console so that it's hard to read test results. So I use jest --silent
.
Devide Cloud Functions' index.ts
Usually we import an index.ts which exports all of Cloud Function's implementations to wrap firebase-functions-test
. But if a function which serves Next.js is contained in it, it becomes difficult to import index.ts because Next.js needs many settings to do so. Therefore, I separated Next.js function and other functions. Only import functions except Next.js one.
src/functions
├── index.ts
├── tsconfig.json
├── __tests__
├── firestore <- Not Next.js functions
└── web <- Next.js function
Mock algolia
My functions use algolia to register my Firestore document to index. Mocking alogolia client is little hard for me. This is how I mocked it.
let mockSaveObject: ReturnType<typeof jest.fn>
jest.mock('algoliasearch', () => {
mockSaveObject = jest.fn().mockReturnValue({})
return {
default: () => ({
initIndex: () => ({
saveObject: mockSaveObject,
}),
}),
}
})
Setup GitHub Actions
This is the diff of setup.
https://github.com/yosan/tennico/pull/14
Workflow Settings
I made settings referring to Cloud Functions runtime environment.
This was my first time to use GitHub Actions. I felt good because workflow settings was simple and I didn't have to write Dockerfile.
Firebase Emulator needs to project ID selection to launch and some credential is needed for it. I specified it from "GitHub > Settings > Secrets".
name: CI
on: [push]
jobs:
test:
runs-on: ubuntu-18.04
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
GCLOUD_PROJECT: ${{ secrets.GCLOUD_PROJECT }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '10.18.1'
- uses: actions/setup-java@v1
with:
java-version: '15.0.2'
java-package: jdk
architecture: x64
- name: Install dependencies
run: yarn
- name: Test
run: yarn test --project ${GCLOUD_PROJECT}
Before I wrote this settings, I found many articles which said using Docker Compose is needed to use Firebase Emulator on GitHub Actions.
Maybe there are some difference we can do between them. But I wanted to do was only to test Cloud Functions and firestore.rules and it seemed that it would become more complex by Docker Compose. So, I did't use it.
functions.config()
If .runtimeconfig
is pushed, functions.config()
can return value. But we shouldn't do that if we published our code on public repository in GitHub.
I set default value to resolve runtime error. For example, when I want to refer algolia API key in Cloud Functions environment variables, I write code like this.
const client = algoliasearch(
functions.config().algolia?.app_id ?? '',
functions.config().algolia?.admin_key ?? ''
)
Ofcource, the client will return error when it calls Algolia API. But we can avoid it by mocking client.
Finally
It works!
Top comments (0)