🔥
rules-unit-testingがv2になったので変更点とともに紹介する
1ヶ月ほど前に、Firestoreのルールの単体テストに使う @firebase/rules-unit-testing
がメジャーバージョンアップデートされました(v1 → v2)。個人的にこのバージョンアップによる改善は、わかりやすくかつ使いやすくなっていて好感を持てたので紹介します。
ちなみに、Firebase JS SDKを v8 → v9 にアップした際に気づきました。
変更点
公式ドキュメントでもしっかり説明されているのでこちらもご参照ください。
TypeScriptで紹介していきます。実際に動いているものが見たい方は以下のリポジトリを見るのが手っ取り早いかと思います。
@firebase/rules-unit-testing
は 2.0.1
で動かしています。
v1(以前までのバージョン)
import { v4 as randomString } from 'uuid'
import * as firebase from '@firebase/rules-unit-testing'
type Auth = {
uid?: string
// other fields are used as request.auth.token in firestore.rules
[key: string]: any
}
const projectId = randomString()
const databaseName = randomString()
// ルールの読み込み
const rules = fs.readFileSync(path.resolve(__dirname, './firestore.rules'), 'utf8')
await firebase.loadFirestoreRules({ projectId, rules })
// firebase-admin でのFirestoreインスタンスを得る
const adminDB = firebase.initializeAdminApp({ projectId, databaseName }).firestore()
// firebase client SDK でのFirestoreインスタンスを得る
const auth: Auth = { uid: randomString() }
const clientDB = firebase.initializeTestApp({ projectId, databaseName, auth }).firestore()
// テスト後のデータ削除
await firebase.clearFirestoreData({ projectId })
- Firestoreのインスタンスを得るには、毎回
projectId, databaseName
を渡していました。- ちょっと面倒だった
- Admin, Client SDKでのFirestoreインスタンスが入り混じっていた
- ルールをバイパスして事前データを作成するにはAdminが必要だった
- あまりないと思うが
serverTimestamp
を Admin の Firestore インスタンスに渡す場合、firebase-admin(Admin SDK)
から得たserverTimestamp
を渡さないとエラーになって面倒だった
v2(新しいバージョン)
import { v4 as randomString } from 'uuid'
import * as firebase from '@firebase/rules-unit-testing'
const projectId = randomString()
// テストプロジェクト環境の作成
const testEnv: firebase.RulesTestEnvironment = await firebase.initializeTestEnvironment({
projectId,
firestore: {
rules: fs.readFileSync('./firestore.rules', 'utf8')
}
})
// ログイン情報つきのContextを作成し、そこから Firestore インスタンスを得る
const authenticatedContext = testEnv.authenticatedContext('uid string')
const clientDB = authenticatedContext.firestore()
// ゲストContextを作成し、そこから Firestore インスタンスを得る
const unauthenticatedContext = testEnv.unauthenticatedContext()
const guestClientDB = unauthenticatedContext.firestore()
// ルールをバイパスしたContextを作成し、そこから Firestore インスタンスを得る
await testEnv.withSecurityRulesDisabled(async context => {
// v1での adminDB のように振る舞えるDB。実態としては Client SDK からのルールが適用されない Firestore インスタンス。
const noRuleDB = context.firestore()
// 事前データの作成など
})
// Firestoreのデータ削除
await testEnv.clearFirestore()
- ある一定のテスト単位ごとに
RulesTestEnvironment
を作成して、すべてはこの変数を通して操作する -
RulesTestEnvironment
自体にprojectId
が設定されるのでいちいち指定する必要がなくなった- databaseName も不要になった(Firebase Firestoreでは指定できないしこのほうが自然)
- すべての Firestore インスタンスは Client SDK からのものになりシンプルになった
-
serverTimestamp
などを渡す場合は、 JS SDKのfirebase/firestore
もしくはimport firebase from 'firebase/compact'
のfirebase.firestore.FieldValue.serverTimestamp()
で渡す -
firebase/compact
はrules-unit-testing
についてくる
-
おわりに
v2になり、かなりシンプルで理解しやすい構造になって、素晴らしい改善だなと感じました。いままでのテストの書き方によっては地味に書き換え箇所が多くなりそうです(実際ボクが担当しているプロジェクトでは結構書き換えが必要だった)。
Discussion
https://github.com/firebase/quickstart-testing が動かなかったので助かりました。
rules-unit-testing v2の全体像つかみ切れてなかったので、日本語コメント付きの記述例が大変参考になりました。
ありがとうございます!