yarn add @firebase/rules-unit-testing --dev
firestore.test.ts のサンプル
import fs from 'fs'
import * as testing from '@firebase/rules-unit-testing'
import * as http from 'http'
const projectId = '<FirebaseのプロジェクトID>'
// カバレッジレポートの出力
const COVERAGE_URL = `http://localhost:8080/emulator/v1/projects/${projectId}:ruleCoverage.html`
afterAll(async () => {
const coverageFile = 'firestore-coverage.html'
const fstream = fs.createWriteStream(coverageFile)
await new Promise((resolve, reject) => {
http.get(COVERAGE_URL, res => {
res.pipe(fstream, { end: true })
res.on('end', resolve)
res.on('error', reject)
})
})
console.log(`● カバレッジレポートを次のURLに出力しました\n${COVERAGE_URL}`)
})
describe('firestore', () => {
let testEnv: testing.RulesTestEnvironment
let userAuthor: testing.RulesTestContext
let userMaintainer: testing.RulesTestContext
let userDoesntHavePermission: testing.RulesTestContext
let userUnauthenticated: testing.RulesTestContext
beforeAll(async () => {
testEnv = await testing.initializeTestEnvironment({
projectId: projectId,
firestore: {
rules: fs.readFileSync('./firebase_emulator/firestore.rules', 'utf8'),
host: 'localhost', // npx jest から実行する場合は必要(firebase emulators:exec からテストする場合は不要)
port: 8080 // npx jest から実行する場合は必要(firebase emulators:exec からテストする場合は不要)
}
})
userAuthor = testEnv.authenticatedContext('test__userAuthor')
userMaintainer = testEnv.authenticatedContext('test__userMaintainer')
userDoesntHavePermission = testEnv.authenticatedContext('test__userDoesntHavePermission')
userUnauthenticated = testEnv.unauthenticatedContext()
// テストデータ作成
await testEnv.withSecurityRulesDisabled(async context => {
// Client SDK からのルールが適用されない Firestore インスタンス。
const noRuleDB = context.firestore()
// 1. (/users/test__userAuthor)
await noRuleDB.doc(`/users/test__userAuthor`).set({
name: 'テストデータ(userAuthor)'
})
// 2. (/users/test__userMaintainer)
await noRuleDB.doc(`/users/test__userMaintainer`).set({
name: 'テストデータ(userMaintainer)',
_permissions: ['/users/test__userAuthor/news']
})
// 3. (/users/test__userDoesntHavePermission)
await noRuleDB.doc(`/users/test__userDoesntHavePermission`).set({
name: 'テストデータ(userDoesntHavePermission)'
})
})
})
afterAll(async () => {
// テストデータ削除
await testEnv.withSecurityRulesDisabled(async context => {
const noRuleDB = context.firestore()
// 1. (/users/test__userAuthor)
await noRuleDB.doc(`/users/test__userAuthor`).delete()
// 2. (/users/test__userMaintainer)
await noRuleDB.doc(`/users/test__userMaintainer`).delete()
// 3. (/users/test__userDoesntHavePermission)
await noRuleDB.doc(`/users/test__userDoesntHavePermission`).delete()
})
})
test('「news/コレクション一覧の読み取り」: ログイン済みユーザ(本人)は読み取ることができる', async () => {
const newList = userAuthor.firestore().collection('/users/test__userAuthor/news').get()
await testing.assertSucceeds(newList)
})
test('「news/コレクション一覧の読み取り」: ログイン前ユーザ(本人)は読み取ることができない', async () => {
const newList = userUnauthenticated.firestore().collection('/users/test__userAuthor/news').get()
await testing.assertFails(newList)
})
test('「news/コレクション一覧の読み取り」: 権限を持たない本人以外のユーザは読み取ることができない', async () => {
const newList = userDoesntHavePermission.firestore().collection('/users/test__userAuthor/news').get()
await testing.assertFails(newList)
})
test('「news/コレクション一覧の読み取り」: 権限を持つ本人以外のユーザは読み取ることができる', async () => {
const newList = userMaintainer.firestore().collection('/users/test__userAuthor/news').get()
await testing.assertSucceeds(newList)
})
})
npx jest firestore.test.ts
FirestoreのカバレッジをGitHubActionsでいい感じに表示する - Qiita
rules-unit-testingがv2になったので変更点とともに紹介する