Firestoreのデータをcopy/exporrt/importできるfsrplを使ってunit testを書く

こんにちは。[もぐめっと](https://mogmet.com)です。
![IMG_9185.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/9655dd57-a466-46c4-6d60-49af9b010675.jpeg)

皆さんは上記を見てなにか叫びたくなりませんか？
是非その叫んだ内容をコメント欄で書いて答え合わせしましょう。

みなさん、fsrplというコマンドを知ってますか？

firestoreのデータをイジイジできるコマンドなんですけど、これが最近気づいたらリリース版になっていて、reference型が対応してなかったのがとうとう対応して超神コマンドと化してしました。


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">fsrplがいつの間にかreference型にも対応してた。とても使えるツールだとおもいます。データのコピペとかimport/exportとかに是非みなさん使ってみるといいと思います！テストデータいれるのにちまちまとコンソールから入れる作業からおさらば！！ <a href="https://twitter.com/hashtag/firebase?src=hash&amp;ref_src=twsrc%5Etfw">#firebase</a> <a href="https://twitter.com/hashtag/firestore?src=hash&amp;ref_src=twsrc%5Etfw">#firestore</a><a href="https://t.co/UVJ23HZzOq">https://t.co/UVJ23HZzOq</a></p>&mdash; もぐめっと＠だいき (@mogmet) <a href="https://twitter.com/mogmet/status/1314446710416916480?ref_src=twsrc%5Etfw">October 9, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

今回はfsrplを使ってセキュリティールールのunit testを書いてみたのでご紹介です。

## fsrplの使い方

[README](https://github.com/matsu0228/fsrpl/blob/master/README_ja.md)にわかりやすく書いてあるので詳細はそちらに譲るとして、大体の使い方とコマンドだけ転載いたします。

インストール

```sh
brew tap matsu0228/homebrew-fsrpl

brew install fsrpl
```

事前準備として最初に環境変数で、firebaseの秘密鍵のjsonのパスを指定しておきます

```sh
export FSRPL_CREDENTIALS=./path/to/adminsdk.json
```

コピーする時

```sh
fsrpl copy [コピー元のドキュメントを指定] --dest [コピー先のドキュメントを指定] 
```

exportする時

```sh
fsrpl dump [コピー元のドキュメントを指定] --path [バックアップファイルを保存するディレクトリを指定]
```

importする時

```sh
fsrpl restore [コピー元のドキュメントを指定] --path [復元対象のJSONファイルを指定]
```

## security ruleのunit testを書く

npmで環境を整えます。こんな感じ。

```json
{
  "scripts": {
    "test": "tsc && FIRESTORE_EMULATOR_HOST=localhost:8080 FIREBASE_DATABASE_EMULATOR_HOST=localhost:9000 npx jest",
    "watch": "npm test -- --watch",
    "emulator:start": "firebase emulators:start --only firestore",
  },
  "devDependencies": {
    "@firebase/app-types": "^0.6.1",
    "@firebase/firestore-types": "^1.13.0",
    "@firebase/rules-unit-testing": "^1.0.7",
    "@types/chai": "^4.2.13",
    "@types/jest": "^26.0.14",
    "filesystem": "1.0.1",
    "jest": "^26.5.2",
    "jest-environment-uint8array": "^1.0.0",
    "mocha": "^8.1.3",
    "source-map-support": "0.5.19",
    "ts-jest": "^26.4.1",
    "ts-node": "9.0.0",
    "tslint": "^6.1.3",
    "typescript": "^4.0.3"
  },
  "dependencies": {
    "firebase-admin": "^9.2.0",
    "jest-environment-node": "^26.0.1"
  }
}

```

FIRESTORE_EMULATOR_HOSTで環境変数をセットておくのが味噌です。
FIREBASE_DATABASE_EMULATOR_HOSTはセットしておかないと警告出てうるさかったので使わないけどセットしておきました。

そしてテストはこんな感じで実装できました

```typescript
import TestProvider from "./TestProvider"
import { execSync } from "child_process";
import * as firebase from "@firebase/rules-unit-testing"
const provider = new TestProvider()
const projectId = "hoge"
const uid = "d5CsSU2fXhUtRx8JqKBbqREVq883"
const clientFirestore = firebase.initializeTestApp({ projectId, databaseName: "dbName", auth: {uid: uid} }).firestore()
const emulatorHost = process.env.FIRESTORE_EMULATOR_HOST
describe('test', () => {
  afterEach(async () => {
    await firebase.clearFirestoreData({projectId: projectId})
  })

  // users
  describe("users collection tests", () => {
    describe("read", () => {
      test("認証してれば読み取れる", async () => {
        const dataPath = "users/*"
        const mockPath = "./mock/users"
        const restoreCmd = `FIRESTORE_EMULATOR_HOST=${emulatorHost} fsrpl restore "${dataPath}" --path "${mockPath}" --debug --emulators-project-id=${projectId}`;
        const stdout = await execSync(`${restoreCmd}`);
        console.warn(`imported test data to ${dataPath}: ${stdout.toString()}`);
        await firebase.assertSucceeds(clientFirestore.doc(`users/${uid}`).get())
      })
    })
  })
})
```

execSyncを通してfsrplを実行することで簡単にテストデータが用意できます！素敵！

テストを実行するときはエミュレータを予め実行しておきます。

```sh
npm run emulator:start
```

別ターミナルでテストを実行。

```sh
npm run test
```

## [@mogmet](https://mogmet.com)の所感

今までは頑張ってコードで書いてデータを準備してましたが、fsrpl使えばjsonでモックデータを準備しておくだけで簡単にテストがかけそうです。

cloud functionsのunit testの時とかに特に重宝するんじゃないかと思います。

欠点をいうと、security ruleでは書き込みの時のテストの時にmockのデータを使いたい感じになると思うんですけど、fsrplだとセキュリティールール通さず直に書き込んでしまってテストにならないので、一回fsrplでロードした後、データをgetして、getしてきたデータを使って書き込みテストするとかになるのかなぁとか構想してますが、なんか二度手間感があるので他にいい方法ご存じの方いたら教えて下さい。

ただ、テスト以外にもコンソールでfirestoreのデータをポチポチ準備するのはつらいんで、積極的にこのコマンドを使ってデータを準備できればと思いました！