YSNHatenaBlog

主にアプリやWebサービス開発について

Firestoreのルールのテストを書いた

Firestore rulesのテストを書いていく。

initializeAdminAppで取得したappでfirestoreに書き込む際、Timestampの型はfirebase-admin由来でないとエラーになった。

Value for argument "data" is not a valid Firestore document. Detected an object of type "Timestamp" that doesn't match the expected instance (found in field "createdAt"). Please ensure that the Firestore types you are using are from the same NPM package.)

Timestampを@firebase/rules-unit-testingではなくfirebase-adminから型を取ったら直った。

次のエラー。

(node:18029) UnhandledPromiseRejectionWarning: Error: FIRESTORE (8.2.5) INTERNAL ASSERTION FAILED: Unexpected state
(node:18029) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 33)

stackoverflow.com

jest --env=node

にする。

また、作成したapp(adminもそうでないのも)は都度delete()で消さないとCI上だとjestが終了しなくなる。 jest --forceExit を使うと終了させることができるが、気持ち悪いなら都度掃除する。

テストコードの最初はこんな感じになった。

import * as firebase from '@firebase/rules-unit-testing'
import * as admin from 'firebase-admin'

const projectId = 'rules-courts-test'

beforeEach(async () => {
    firebase.loadFirestoreRules({
        projectId,
        rules: fs.readFileSync('firestore.rules', 'utf8'),
    })

    const adminApp = firebase.initializeAdminApp({ projectId })
    // adminAppを使ってテストの初期状態となるデータを書き込んでいく
    await adminApp.delete()
})

afterEach(async () => {
    await firebase.clearFirestoreData({ projectId })

})

また、公式ガイドだとassertSucceeds, assertFailsはawait無しで書いてあるので、もしやいらない?と思ったが、awaitしないと正しいテスト結果にならなかった。

test('read shoud be succeeded', async () => {
    await firebase.assertSucceeds(
        app.firestore().collection('courts').doc('Slsnk6XjulO3ndipFjlY').get()
    )
})

Youtubeでもawait入れてるしよさそう。

www.youtube.com

実際の差分はこうなった。

github.com