Open7

Firebase Emulatorで開発するまで

cotaponcotapon

firebase-tools

npm i -g でインストールしてもいいけど、グローバルにインストールしなくても npxfirebase コマンドを使えばいい。

$ npx -p firebase-tools -c 'firebase login'

こうするとブラウザが起動してfirebaseにログインする。

$ npx firebase-tools login

でも実行できるみたいやねんけど、どっちがいいんやろか。

cotaponcotapon

firebase init

npx -p firebase-tools -c 'firebase init'

色々質問されるのでてきとーに答える。 firebase.json ができるので中身を見てみる。

firebase.json
{
  "firestore": {
    "rules": "firestore.rules",
    "indexes": "firestore.indexes.json"
  },
  "emulators": {
    "firestore": {
      "port": "8080"
    },
    "auth": {
      "port": "9099"
    }
  }
}

emulatorsfirestoreauth がある。ほかにも functionspubsub もエミュレーターできる。
https://firebase.google.com/docs/emulator-suite/install_and_configure?hl=ja

cotaponcotapon

エミュレータの起動

$ npx -p firebase-tools -c 'firebase emulators:start --project test --import=./data/firebase --export-on-exit=./data/firebase'

rootディレクトリに ./daat/firebase 作っておけば、エミュレータで追加したデータがここに保管される。 --export-on-exit オプションでつければ、エミュレータ終了時にexportしてくれる

http://localhost:4000/ でエミュレータの管理画面にアクセスができる。

cotaponcotapon

firestore.rules

firestore.rules
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /public/v1/users/{userId} {
      allow read: if isAuthUser(request.auth, userId);
    }
  }
}

ちょっと雑ですがこんな感じのルールを作ってみます。

rulesのdeploy

$ npx -p firebase-tools -c 'firebase deploy --only firestore:rules --project プロジェクトID'

成功するとこんな感じのログが出る

i  deploying firestore
i  cloud.firestore: checking firestore.rules for compilation errors...
✔  cloud.firestore: rules file firestore.rules compiled successfully
i  firestore: uploading rules firestore.rules...
✔  firestore: released rules firestore.rules to cloud.firestore

✔  Deploy complete!
cotaponcotapon

firestore rules testing

先人の知恵をお借りする。firebaseのテストライブラリ @firebase/testing はもう非推奨みたいで、 @firebase/rules-unit-testing が推奨みたい。 @firebase/testing で書かれている内容でもテストコードは大きくは変わりません。

https://qiita.com/ryo2132/items/02b4d341fb01f04ec0be
https://github.com/kawamataryo/practice-firestore-rule-test
https://zenn.dev/kinmi/articles/firestore-rules-jest
https://qiita.com/sgr-ksmt/items/1a731fdadf06119d35fc

package.json

package.json
"test": "jest --detectOpenHandles ./src && npm run test:firestore",
"test:firestore": "npx -p firebase-tools -c 'firebase emulators:exec --only firestore \"jest __tests__/firestore --detectOpenHandles\"'",

jest.config

firestoreのテストコードは作業ディレクトリというよりルートディレクトリに __tests___/firestore を作ったほうがいいような気がする。

.
├── README.md
├── __tests__
 │         └── firestore
├── data
├── firebase.json
├── firestore-debug.log
├── firestore.indexes.json
├── firestore.rules
├── jest.config.js
├── next-env.d.ts
├── next.config.js
├── node_modules
├── package.json
├── public
├── src
├── tsconfig.json
└── yarn.lock

ということで、 jest.config.jsmoduleNameMapper はこんな感じになると思います。

jest.config.js
  moduleNameMapper: {
    // "src(.*)$": "<rootDir>/src/$1",
    "^@/(.*)$": "<rootDir>/$1",
    "\\.(css|less|sass|scss)$": "identity-obj-proxy",
    "\\.(gif|ttf|eot|svg|png)$": "<rootDir>/test/__mocks__/fileMock.js",
  },
cotaponcotapon

Emulatorが起動しない場合

だいたい起動しない原因は、エミュレータを止める時にCtrl + C を連打して、止めるプロセス自体も止めてしまって裏でずーっと動いてることになってる場合やと思います。連打をやめるのを心がけてます。。。

⚠  firestore: Port 8080 is not open on localhost, could not start Firestore Emulator.
⚠  firestore: To select a different host/port, specify that host/port in a firebase.json config file:
      {
        // ...
        "emulators": {
          "firestore": {
            "host": "HOST",
            "port": "PORT"
          }
        }
      }
i  emulators: Shutting down emulators.

こんな感じのエラーが出たら動いてるプロセスを突き止めて kill しちゃいます。

$ lsof -i:8080
COMMAND   PID   USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
java    59688 user  206u  IPv6 0xe8af525e1bd56c65      0t0  TCP localhost:http-alt (LISTEN)
java    59688 user  208u  IPv6 0xe8af525e1bd59125      0t0  TCP localhost:61371->localhost:http-alt (ESTABLISHED)
java    59688 user  209u  IPv6 0xe8af525e1bd58b05      0t0  TCP localhost:http-alt->localhost:61371 (ESTABLISHED)

javaで動いてるのでjavaもろともkillします。

$ pkill java

4000portも動いてるか見ます。

 $ lsof -i:4000
COMMAND     PID   USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
node      53308 user   23u  IPv4 0xe8af525e17b5bf35      0t0  TCP localhost:terabase (LISTEN)
node      53308 user   26u  IPv4 0xe8af525e445db555      0t0  TCP localhost:terabase->localhost:55184 (ESTABLISHED)

PIDをコピってkillします

$ kill -9 53308

これで起動しなくなったエミュレータが起動するようになると思います。