Firebase Local Emulator Suite を使用すると、アプリの機能と動作を完全に検証しやすくなります。また、Firebase セキュリティ ルールの構成を確認するための優れたツールでもあります。 Firebase Emulators を使用して、ローカル環境で単体テストを実行および自動化します。このドキュメントで概説されている方法は、ルールを検証するアプリの単体テストを構築および自動化する際に役立ちます。
Firebase Emulators をまだセットアップしていない場合は、セットアップします。
エミュレータを実行する前に
エミュレーターの使用を開始する前に、次の点に注意してください。
- エミュレーターは最初に、
firebase.json
ファイルのfirestore.rules
または 'storage.rules' フィールドで指定されたルールを読み込みます。ファイルが存在せず、以下で説明するようにloadFirestoreRules
または 'loadStorageRules' メソッドを使用しない場合、エミュレーターはすべてのプロジェクトをオープン ルールを持つものとして扱います。 - ほとんどの Firebase SDKはエミュレーターと直接連携しますが、
@firebase/rules-unit-testing
ライブラリのみがセキュリティ ルールでauth
のモックをサポートしているため、単体テストがはるかに簡単になります。さらに、ライブラリは、以下に示すように、すべてのデータを消去するなど、エミュレーター固有の機能をいくつかサポートしています。 - エミュレーターは、クライアント SDK を介して提供される本番用の Firebase Auth トークンも受け入れ、それに応じてルールを評価します。これにより、統合および手動テストでアプリケーションをエミュレーターに直接接続できます。
データベース エミュレーターと本番環境の違い
- データベース インスタンスを明示的に作成する必要はありません。エミュレーターは、アクセスされるすべてのデータベース インスタンスを自動的に作成します。
- 新しいデータベースはそれぞれクローズド ルールで開始されるため、管理者以外のユーザーは読み書きできません。
- エミュレートされた各データベースには、 Spark プランの制限とクォータが適用されます (最も顕著なのは、これにより、各インスタンスが 100 の同時接続に制限されます)。
- どのデータベースも、文字列
"owner"
を管理者認証トークンとして受け入れます。 - エミュレーターは現在、他の Firebase プロダクトと連携して機能していません。特に、通常の Firebase Authentication フローは機能しません。代わりに、
auth
フィールドを受け取るrules-unit-testing
ライブラリのinitializeTestApp()
メソッドを使用できます。このメソッドを使用して作成された Firebase オブジェクトは、指定したエンティティとして認証に成功したかのように動作します。null
を渡すと、認証されていないユーザーとして動作します (たとえば、auth != null
ルールは失敗します)。
Realtime Database エミュレーターの操作
実稼働の Firebase Realtime Database インスタンスは、 firebaseio.com
のサブドメインでアクセスでき、次のように REST API にアクセスできます。
https://<database_name>.firebaseio.com/path/to/my/data.json
エミュレーターはローカルで実行され、 localhost:9000
で利用できます。特定のデータベース インスタンスとやり取りするには、 ns
クエリ パラメーターを使用してデータベース名を指定する必要があります。
http://localhost:9000/path/to/my/data.json?ns=<database_name>
バージョン 9 JavaScript SDK を使用してローカル単体テストを実行する
Firebase は、バージョン 9 の JavaScript SDK とバージョン 8 の SDK の両方を備えたセキュリティ ルールの単体テスト ライブラリを配布しています。ライブラリ API は大きく異なります。 v9 テスト ライブラリをお勧めします。これはより合理化されており、エミュレーターに接続するためのセットアップが少なくて済むため、運用リソースの誤った使用を安全に回避できます。下位互換性のために、引き続きv8 テスト ライブラリを利用できます。
@firebase/rules-unit-testing
モジュールを使用して、ローカルで実行されるエミュレーターとやり取りします。タイムアウトまたはECONNREFUSED
エラーが発生した場合は、エミュレータが実際に実行されていることを再確認してください。
async/await
表記を使用できるように、最新バージョンの Node.js を使用することを強くお勧めします。テストする可能性のあるほとんどすべての動作には非同期関数が含まれており、テスト モジュールは Promise ベースのコードで動作するように設計されています。
v9 Rules Unit Testing ライブラリは、常にエミュレーターを認識しており、実稼働リソースに触れることはありません。
v9 モジュラー インポート ステートメントを使用してライブラリをインポートします。例えば:
import {
assertFails,
assertSucceeds,
initializeTestEnvironment,
RulesTestEnvironment,
} from "@firebase/rules-unit-testing"
// Use `const { … } = require("@firebase/rules-unit-testing")` if imports are not supported
// Or we suggest `const testing = require("@firebase/rules-unit-testing")` if necessary.
インポートしたら、単体テストの実装には次の作業が含まれます。
-
initializeTestEnvironment
を呼び出してRulesTestEnvironment
を作成および構成します。 -
RulesTestEnvironment.withSecurityRulesDisabled
を一時的にバイパスできる便利なメソッドを使用して、Rules をトリガーせずにテスト データを設定します。 -
RulesTestEnvironment.cleanup()
やRulesTestEnvironment.clearFirestore()
) などのテスト データと環境をクリーンアップするための呼び出しを使用して、テスト スイートとテストごとの前後フックを設定します。 -
RulesTestEnvironment.authenticatedContext
およびRulesTestEnvironment.unauthenticatedContext
を使用して、認証状態を模倣するテスト ケースを実装します。
一般的なメソッドとユーティリティ関数
v9 SDK のエミュレーター固有のテスト メソッドも参照してください。
initializeTestEnvironment() => RulesTestEnvironment
この関数は、ルールの単体テスト用のテスト環境を初期化します。テストのセットアップのために、最初にこの関数を呼び出します。正常に実行するには、エミュレーターが実行されている必要があります。
この関数は、プロジェクト ID とエミュレーター構成設定で構成できるTestEnvironmentConfig
を定義するオプションのオブジェクトを受け入れます。
let testEnv = await initializeTestEnvironment({ projectId: "demo-project-1234", firestore: { rules: fs.readFileSync("firestore.rules", "utf8"), }, });
RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext
このメソッドは、認証された Authentication ユーザーのように動作するRulesTestContext
を作成します。返されたコンテキストを介して作成されたリクエストには、モック認証トークンが添付されます。必要に応じて、認証トークン ペイロードのカスタム クレームまたはオーバーライドを定義するオブジェクトを渡します。
返されたテスト コンテキスト オブジェクトをテストで使用して、 initializeTestEnvironment
で構成されたものを含め、構成されたエミュレーター インスタンスにアクセスします。
// Assuming a Firestore app and the Firestore emulator for this example import { setDoc } from "firebase/firestore"; const alice = testEnv.authenticatedContext("alice", { … }); // Use the Firestore instance associated with this context await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });
RulesTestEnvironment.unauthenticatedContext() => RulesTestContext
このメソッドは、Authentication 経由でログインしていないクライアントのように動作するRulesTestContext
を作成します。返されたコンテキストを介して作成されたリクエストには、Firebase Auth トークンが添付されません。
返されたテスト コンテキスト オブジェクトをテストで使用して、 initializeTestEnvironment
で構成されたものを含め、構成されたエミュレーター インスタンスにアクセスします。
// Assuming a Cloud Storage app and the Storage emulator for this example import { getStorage, ref, deleteObject } from "firebase/storage"; const alice = testEnv.unauthenticatedContext(); // Use the Cloud Storage instance associated with this context const desertRef = ref(alice.storage(), 'images/desert.jpg'); await assertSucceeds(deleteObject(desertRef));
RulesTestEnvironment.withSecurityRulesDisabled()
セキュリティ ルールが無効になっているかのように動作するコンテキストでテスト セットアップ関数を実行します。
このメソッドは、Security-Rules-bypassing コンテキストを取得して promise を返すコールバック関数を受け取ります。プロミスが解決/拒否されると、コンテキストは破棄されます。
RulesTestEnvironment.cleanup()
このメソッドは、テスト環境で作成されたすべてのRulesTestContexts
を破棄し、基礎となるリソースをクリーンアップして、クリーンな終了を可能にします。
このメソッドは、エミュレーターの状態を変更しません。テスト間でデータをリセットするには、アプリケーション エミュレータ固有のクリア データ メソッドを使用します。
assertSucceeds(pr: Promise<any>)) => Promise<any>
これはテスト ケースのユーティリティ関数です。
この関数は、エミュレータ操作をラップする提供された Promise がセキュリティ ルール違反なしで解決されることをアサートします。
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });
assertFails(pr: Promise<any>)) => Promise<any>
これはテスト ケースのユーティリティ関数です。
この関数は、エミュレータ操作をラップする提供された Promise がセキュリティ ルール違反で拒否されることをアサートします。
await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });
エミュレータ固有のメソッド
v9 SDK の一般的なテスト メソッドとユーティリティ関数も参照してください。
クラウド ファイアストア
クラウド ファイアストア
RulesTestEnvironment.clearFirestore() => Promise<void>
このメソッドは、Firestore エミュレータ用に構成されたprojectId
に属する Firestore データベースのデータを消去します。
RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;
このメソッドは、このテスト コンテキストの Firestore インスタンスを取得します。返された Firebase JS クライアント SDK インスタンスは、クライアント SDK API (v9 モジュラーまたは v9 互換) で使用できます。
リアルタイム データベース
リアルタイム データベース
RulesTestEnvironment.clearDatabase() => Promise<void>
このメソッドは、Realtime Database エミュレータ用に構成されたprojectId
に属する Realtime Database のデータを消去します。
RulesTestContext.database(databaseURL?: Firestore.FirestoreSettings) => Firestore;
このテスト コンテキストの Realtime Database インスタンスを取得します。返された Firebase JS クライアント SDK インスタンスは、クライアント SDK API (v9 モジュラーまたは v9 互換) で使用できます。このメソッドは、Realtime Database インスタンスの URL を受け入れます。指定されている場合、URL から抽出されたパラメーターを使用して、名前空間のエミュレートされたバージョンのインスタンスを返します。
クラウドストレージ
クラウドストレージ
RulesTestEnvironment.clearStorage() => Promise<void>
このメソッドは、Cloud Storage エミュレータ用に構成されたprojectId
に属するストレージ バケット内のオブジェクトとメタデータをクリアします。
RulesTestContext.storage(bucketUrl?: string) => Firebase Storage;
このメソッドは、エミュレーターに接続するように構成された Storage インスタンスを返します。このメソッドは、テスト用に Firebase Storage バケットへのgs://
URL を受け入れます。指定されている場合、バケット名のエミュレートされたバージョンの Storage インスタンスを返します。
v8 JavaScript SDK を使用してローカル単体テストを実行する
製品を選択して、Firebase Test SDK がエミュレータとのインターフェースに使用するメソッドを確認してください。
クラウド ファイアストア
initializeTestApp({ projectId: string, auth: Object }) => FirebaseApp
このメソッドは、オプションで指定されたプロジェクト ID と auth 変数に対応する初期化された Firebase アプリを返します。これを使用して、テストで使用する特定のユーザーとして認証されたアプリを作成します。
firebase.initializeTestApp({ projectId: "my-test-project", auth: { uid: "alice", email: "alice@example.com" } });
initializeAdminApp({ projectId: string }) => FirebaseApp
このメソッドは、初期化された管理 Firebase アプリを返します。このアプリは、読み取りと書き込みを実行するときにセキュリティ ルールをバイパスします。これを使用して、管理者として認証されたアプリを作成し、テストの状態を設定します。
firebase.initializeAdminApp({ projectId: "my-test-project" });
apps() => [FirebaseApp]
このメソッドは、現在初期化されているすべてのテスト アプリと管理アプリを返します。これを使用して、テスト間またはテスト後にアプリをクリーンアップします。
Promise.all(firebase.apps().map(app => app.delete()))
loadFirestoreRules({ projectId: string, rules: Object }) => Promise
このメソッドは、ローカルで実行中のデータベースにルールを送信します。ルールを文字列として指定するオブジェクトを取ります。このメソッドを使用して、データベースのルールを設定します。
firebase.loadFirestoreRules({ projectId: "my-test-project", rules: fs.readFileSync("/path/to/firestore.rules", "utf8") });
assertFails(pr: Promise) => Promise
このメソッドは、入力が成功した場合に拒否されるか、入力が拒否された場合に成功する promise を返します。これを使用して、データベースの読み取りまたは書き込みが失敗したかどうかをアサートします。
firebase.assertFails(app.firestore().collection("private").doc("super-secret-document").get());
assertSucceeds(pr: Promise) => Promise
このメソッドは、入力が成功した場合は成功し、入力が拒否された場合は拒否される promise を返します。これを使用して、データベースの読み取りまたは書き込みが成功したかどうかをアサートします。
firebase.assertSucceeds(app.firestore().collection("public").doc("test-document").get());
clearFirestoreData({ projectId: string }) => Promise
このメソッドは、ローカルで実行されている Firestore インスタンス内の特定のプロジェクトに関連付けられているすべてのデータを消去します。このメソッドを使用して、テスト後にクリーンアップします。
firebase.clearFirestoreData({ projectId: "my-test-project" });
リアルタイム データベース
リアルタイム データベース
initializeTestApp({ databaseName: string, auth: Object }) => FirebaseApp
これを使用して、テストで使用する特定のユーザーとして認証されたアプリを作成します。
オプションで指定されたデータベース名と認証変数オーバーライドに対応する、初期化された Firebase アプリを返します。
firebase.initializeTestApp({
databaseName: "my-database",
auth: { uid: "alice" }
});
initializeAdminApp({ databaseName: string }) => FirebaseApp
これを使用して、管理者として認証されたアプリを作成し、テストの状態を設定します。
オプションで指定されたデータベース名に対応する、初期化された管理 Firebase アプリを返します。このアプリは、データベースの読み取りおよび書き込み時にセキュリティ ルールをバイパスします。
firebase.initializeAdminApp({ databaseName: "my-database" });
loadDatabaseRules({ databaseName: string, rules: Object }) => Promise
これを使用して、データベースのルールを設定します。
ローカルで実行中のデータベースにルールを送信します。 「databaseName」と「rules」を文字列として指定するオプション オブジェクトを受け取ります。
firebase
.loadDatabaseRules({
databaseName: "my-database",
rules: "{'rules': {'.read': false, '.write': false}}"
});
apps() => [FirebaseApp]
現在初期化されているすべてのテスト アプリと管理アプリを返します。
これを使用して、テスト間またはテスト後にアプリをクリーンアップします (アクティブなリスナーで初期化されたアプリは JavaScript を終了できないことに注意してください)。
Promise.all(firebase.apps().map(app => app.delete()))
assertFails(pr: Promise) => Promise
入力が成功した場合は拒否され、入力が拒否された場合は成功する promise を返します。
これを使用して、データベースの読み取りまたは書き込みが失敗したことをアサートします。
firebase.assertFails(app.database().ref("secret").once("value"));
assertSucceeds(pr: Promise) => Promise
入力が成功した場合は成功し、入力が拒否された場合は拒否される promise を返します。
これを使用して、データベースの読み取りまたは書き込みが成功したことをアサートします。
firebase.assertSucceeds(app.database().ref("public").once("value"));
クラウドストレージ
クラウドストレージ
initializeTestApp({ storageBucket: string, auth: Object }) => FirebaseApp
これを使用して、テストで使用する特定のユーザーとして認証されたアプリを作成します。
オプションで指定されたストレージ バケット名と認証変数のオーバーライドに対応する、初期化された Firebase アプリを返します。
firebase.initializeTestApp({
storageBucket: "my-bucket",
auth: { uid: "alice" }
});
initializeAdminApp({ storageBucket: string }) => FirebaseApp
これを使用して、管理者として認証されたアプリを作成し、テストの状態を設定します。
オプションで指定されたストレージ バケット名に対応する、初期化された管理 Firebase アプリを返します。このアプリは、バケットの読み取りおよび書き込み時にセキュリティ ルールをバイパスします。
firebase.initializeAdminApp({ storageBucket: "my-bucket" });
loadStorageRules({ storageBucket: string, rules: Object }) => Promise
これを使用して、ストレージ バケットのルールを設定します。
ローカルで管理されているストレージ バケットにルールを送信します。 「storageBucket」と「rules」を文字列として指定するオプション オブジェクトを受け取ります。
firebase
.loadStorageRules({
storageBucket: "my-bucket",
rules: fs.readFileSync("/path/to/storage.rules", "utf8")
});
apps() => [FirebaseApp]
現在初期化されているすべてのテスト アプリと管理アプリを返します。
これを使用して、テスト間またはテスト後にアプリをクリーンアップします (アクティブなリスナーで初期化されたアプリは JavaScript を終了できないことに注意してください)。
Promise.all(firebase.apps().map(app => app.delete()))
assertFails(pr: Promise) => Promise
入力が成功した場合は拒否され、入力が拒否された場合は成功する promise を返します。
これを使用して、ストレージ バケットの読み取りまたは書き込みが失敗したことをアサートします。
firebase.assertFails(app.storage().ref("letters/private.doc").getMetadata());
assertSucceeds(pr: Promise) => Promise
入力が成功した場合は成功し、入力が拒否された場合は拒否される promise を返します。
これを使用して、ストレージ バケットの読み取りまたは書き込みが成功したことをアサートします。
firebase.assertFails(app.storage().ref("images/cat.png").getMetadata());
JS SDK v8 の RUT ライブラリ API
製品を選択して、Firebase Test SDK がエミュレータとのインターフェースに使用するメソッドを確認してください。
クラウド ファイアストア
クラウド ファイアストア
initializeTestApp({ projectId: string, auth: Object }) => FirebaseApp
このメソッドは、オプションで指定されたプロジェクト ID と auth 変数に対応する初期化された Firebase アプリを返します。これを使用して、テストで使用する特定のユーザーとして認証されたアプリを作成します。
firebase.initializeTestApp({ projectId: "my-test-project", auth: { uid: "alice", email: "alice@example.com" } });
initializeAdminApp({ projectId: string }) => FirebaseApp
このメソッドは、初期化された管理 Firebase アプリを返します。このアプリは、読み取りと書き込みを実行するときにセキュリティ ルールをバイパスします。これを使用して、管理者として認証されたアプリを作成し、テストの状態を設定します。
firebase.initializeAdminApp({ projectId: "my-test-project" });
apps() => [FirebaseApp]
このメソッドは、現在初期化されているすべてのテスト アプリと管理アプリを返します。これを使用して、テスト間またはテスト後にアプリをクリーンアップします。
Promise.all(firebase.apps().map(app => app.delete()))
loadFirestoreRules({ projectId: string, rules: Object }) => Promise
このメソッドは、ローカルで実行中のデータベースにルールを送信します。ルールを文字列として指定するオブジェクトを取ります。このメソッドを使用して、データベースのルールを設定します。
firebase.loadFirestoreRules({ projectId: "my-test-project", rules: fs.readFileSync("/path/to/firestore.rules", "utf8") });
assertFails(pr: Promise) => Promise
このメソッドは、入力が成功した場合に拒否されるか、入力が拒否された場合に成功する promise を返します。これを使用して、データベースの読み取りまたは書き込みが失敗したかどうかをアサートします。
firebase.assertFails(app.firestore().collection("private").doc("super-secret-document").get());
assertSucceeds(pr: Promise) => Promise
このメソッドは、入力が成功した場合は成功し、入力が拒否された場合は拒否される promise を返します。これを使用して、データベースの読み取りまたは書き込みが成功したかどうかをアサートします。
firebase.assertSucceeds(app.firestore().collection("public").doc("test-document").get());
clearFirestoreData({ projectId: string }) => Promise
このメソッドは、ローカルで実行されている Firestore インスタンス内の特定のプロジェクトに関連付けられているすべてのデータを消去します。このメソッドを使用して、テスト後にクリーンアップします。
firebase.clearFirestoreData({ projectId: "my-test-project" });
リアルタイム データベース
リアルタイム データベース
initializeTestApp({ databaseName: string, auth: Object }) => FirebaseApp
これを使用して、テストで使用する特定のユーザーとして認証されたアプリを作成します。
オプションで指定されたデータベース名と認証変数オーバーライドに対応する、初期化された Firebase アプリを返します。
firebase.initializeTestApp({
databaseName: "my-database",
auth: { uid: "alice" }
});
initializeAdminApp({ databaseName: string }) => FirebaseApp
これを使用して、管理者として認証されたアプリを作成し、テストの状態を設定します。
オプションで指定されたデータベース名に対応する、初期化された管理 Firebase アプリを返します。このアプリは、データベースの読み取りおよび書き込み時にセキュリティ ルールをバイパスします。
firebase.initializeAdminApp({ databaseName: "my-database" });
loadDatabaseRules({ databaseName: string, rules: Object }) => Promise
これを使用して、データベースのルールを設定します。
ローカルで実行中のデータベースにルールを送信します。 「databaseName」と「rules」を文字列として指定するオプション オブジェクトを受け取ります。
firebase
.loadDatabaseRules({
databaseName: "my-database",
rules: "{'rules': {'.read': false, '.write': false}}"
});
apps() => [FirebaseApp]
現在初期化されているすべてのテスト アプリと管理アプリを返します。
これを使用して、テスト間またはテスト後にアプリをクリーンアップします (アクティブなリスナーで初期化されたアプリは JavaScript を終了できないことに注意してください)。
Promise.all(firebase.apps().map(app => app.delete()))
assertFails(pr: Promise) => Promise
入力が成功した場合は拒否され、入力が拒否された場合は成功する promise を返します。
これを使用して、データベースの読み取りまたは書き込みが失敗したことをアサートします。
firebase.assertFails(app.database().ref("secret").once("value"));
assertSucceeds(pr: Promise) => Promise
入力が成功した場合は成功し、入力が拒否された場合は拒否される promise を返します。
これを使用して、データベースの読み取りまたは書き込みが成功したことをアサートします。
firebase.assertSucceeds(app.database().ref("public").once("value"));
クラウドストレージ
クラウドストレージ
initializeTestApp({ storageBucket: string, auth: Object }) => FirebaseApp
これを使用して、テストで使用する特定のユーザーとして認証されたアプリを作成します。
オプションで指定されたストレージ バケット名と認証変数のオーバーライドに対応する、初期化された Firebase アプリを返します。
firebase.initializeTestApp({
storageBucket: "my-bucket",
auth: { uid: "alice" }
});
initializeAdminApp({ storageBucket: string }) => FirebaseApp
これを使用して、管理者として認証されたアプリを作成し、テストの状態を設定します。
オプションで指定されたストレージ バケット名に対応する、初期化された管理 Firebase アプリを返します。このアプリは、バケットの読み取りおよび書き込み時にセキュリティ ルールをバイパスします。
firebase.initializeAdminApp({ storageBucket: "my-bucket" });
loadStorageRules({ storageBucket: string, rules: Object }) => Promise
これを使用して、ストレージ バケットのルールを設定します。
ローカルで管理されているストレージ バケットにルールを送信します。 「storageBucket」と「rules」を文字列として指定するオプション オブジェクトを受け取ります。
firebase
.loadStorageRules({
storageBucket: "my-bucket",
rules: fs.readFileSync("/path/to/storage.rules", "utf8")
});
apps() => [FirebaseApp]
現在初期化されているすべてのテスト アプリと管理アプリを返します。
これを使用して、テスト間またはテスト後にアプリをクリーンアップします (アクティブなリスナーで初期化されたアプリは JavaScript を終了できないことに注意してください)。
Promise.all(firebase.apps().map(app => app.delete()))
assertFails(pr: Promise) => Promise
入力が成功した場合は拒否され、入力が拒否された場合は成功する promise を返します。
これを使用して、ストレージ バケットの読み取りまたは書き込みが失敗したことをアサートします。
firebase.assertFails(app.storage().ref("letters/private.doc").getMetadata());
assertSucceeds(pr: Promise) => Promise
入力が成功した場合は成功し、入力が拒否された場合は拒否される promise を返します。
これを使用して、ストレージ バケットの読み取りまたは書き込みが成功したことをアサートします。
firebase.assertFails(app.storage().ref("images/cat.png").getMetadata());