Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Menguji Aturan Keamanan Cloud Firestore

Saat membuat aplikasi, Anda mungkin ingin mengunci akses ke database Cloud Firestore. Namun, sebelum memulai, Anda memerlukan Aturan Keamanan Cloud Firestore yang lebih tertata. Dengan emulator Cloud Firestore, Anda dapat menulis pengujian unit yang akan memeriksa perilaku Aturan Keamanan Cloud Firestore Anda.

Panduan Memulai

Untuk beberapa kasus pengujian dasar dengan aturan sederhana, cobalah contoh panduan memulai.

Memahami Aturan Keamanan Cloud Firestore

Terapkan Firebase Authentication dan Aturan Keamanan Cloud Firestore untuk autentikasi otorisasi, serta validasi data tanpa server saat Anda menggunakan library klien seluler dan web. .

Aturan Keamanan Cloud Firestore mencakup dua bagian:

  1. Pernyataan match yang mengidentifikasi dokumen dalam database Anda.
  2. Ekspresi allow yang mengontrol akses ke dokumen tersebut.

Firebase Authentication memverifikasi kredensial pengguna dan memberikan landasan untuk sistem akses berbasis pengguna dan peran.

Sebelum membaca atau menulis data, setiap permintaan database dari library klien seluler/web Cloud Firestore dievaluasi terhadap aturan keamanan Anda. Apabila aturan tersebut menolak akses ke salah satu jalur dokumen yang ditentukan, seluruh permintaan akan gagal.

Pelajari lebih lanjut Aturan Keamanan Cloud Firestore di Memulai Aturan Keamanan Cloud Firestore.

Menginstal emulator

Untuk menginstal emulator Cloud Firestore, gunakan Firebase CLI dan jalankan perintah di bawah:

firebase setup:emulators:firestore

Menjalankan emulator

Mulai dengan menginisialisasi project Firebase di direktori kerja Anda. Ini adalah langkah pertama yang umum saat menggunakan Firebase CLI.

firebase init

Mulai emulator menggunakan perintah berikut. Emulator akan berjalan hingga Anda menghentikan prosesnya:

firebase emulators:start --only firestore

Dalam sebagian besar kasus, sebaiknya Anda memulai emulator, menjalankan serangkaian pengujian, lalu menghentikan emulator setelah pengujian berjalan. Anda dapat melakukannya dengan mudah menggunakan perintah emulators:exec:

firebase emulators:exec --only firestore "./my-test-script.sh"

Ketika perintah mulai dijalankan, emulator akan mencoba berjalan pada port default (8080). Anda dapat mengubah port emulator dengan mengubah bagian "emulators" pada file firebase.json Anda:

{
  // ...
  "emulators": {
    "firestore": {
      "port": "YOUR_PORT"
    }
  }
}

Sebelum menjalankan emulator

Sebelum Anda mulai menggunakan emulator, perhatikan hal-hal berikut:

  • Pertama, emulator akan memuat aturan yang ditentukan dalam kolom firestore.rules file firebase.json Anda. Emulator akan mencari nama file lokal yang berisi Aturan Keamanan Cloud Firestore dan menerapkan aturan tersebut untuk semua project. Jika Anda tidak memberikan jalur file lokal atau menggunakan metode loadFirestoreRules seperti yang dijelaskan di bawah, emulator akan memperlakukan semua project dengan aturan terbuka.
  • Meskipun sebagian besar Firebase SDK bekerja dengan emulator secara langsung, hanya library @firebase/rules-unit-testing yang mendukung pembuatan auth di Aturan Keamanan, sehingga pengujian unit menjadi lebih mudah. Selain itu, library ini mendukung beberapa fitur khusus emulator seperti menghapus semua data, seperti yang tercantum di bawah ini.
  • Emulator juga akan menerima token Firebase Auth produksi yang disediakan melalui SDK Klien dan mengevaluasi aturan yang sesuai, agar aplikasi Anda dapat terhubung langsung ke emulator dalam integrasi dan pengujian manual.

Menjalankan pengujian lokal

initializeTestApp({ projectId: string, auth: Object }) => FirebaseApp

Metode ini menampilkan aplikasi Firebase yang diinisialisasi sesuai dengan project ID dan variabel autentikasi yang ditentukan pada opsi. Gunakan metode ini untuk membuat aplikasi yang diautentikasi sebagai pengguna khusus untuk digunakan pada pengujian.

firebase.initializeTestApp({
  projectId: "my-test-project",
  auth: { uid: "alice", email: "alice@example.com" }
});

initializeAdminApp({ projectId: string }) => FirebaseApp

Metode ini menampilkan aplikasi Firebase admin yang diinisialisasi. Aplikasi ini mengabaikan aturan keamanan saat melakukan pembacaan dan penulisan. Gunakan metode ini untuk membuat aplikasi yang diautentikasi sebagai admin guna menetapkan status untuk pengujian.

firebase.initializeAdminApp({ projectId: "my-test-project" });
    

apps() => [FirebaseApp] Metode ini menampilkan semua pengujian dan aplikasi admin yang saat ini diinisialisasi. Gunakan metode ini untuk menghapus data aplikasi antar-pengujian atau setelah pengujian.

Promise.all(firebase.apps().map(app => app.delete()))

loadFirestoreRules({ projectId: string, rules: Object }) => Promise

Metode ini mengirim aturan ke database yang berjalan secara lokal. Diperlukan objek yang menentukan aturan sebagai string. Gunakan metode ini untuk menetapkan aturan database Anda.

firebase.loadFirestoreRules({
  projectId: "my-test-project",
  rules: fs.readFileSync("/path/to/firestore.rules", "utf8")
});
    

assertFails(pr: Promise) => Promise

Metode ini menampilkan promise yang ditolak jika input berhasil, atau promise yang berhasil jika input ditolak. Gunakan metode ini untuk menegaskan jika pembacaan atau penulisan database gagal.

firebase.assertFails(app.firestore().collection("private").doc("super-secret-document").get());
    

assertSucceeds(pr: Promise) => Promise

Metode ini menghasilkan promise yang berhasil jika input berhasil, dan promise yang ditolak jika input ditolak. Gunakan metode ini untuk menegaskan jika pembacaan atau penulisan database berhasil.

firebase.assertSucceeds(app.firestore().collection("public").doc("test-document").get());
    

clearFirestoreData({ projectId: string }) => Promise

Metode ini menghapus semua data yang terkait dengan project tertentu pada instance Firestore yang berjalan secara lokal. Gunakan metode ini untuk melakukan pembersihan setelah pengujian.

firebase.clearFirestoreData({
  projectId: "my-test-project"
});
   

Menghasilkan laporan pengujian

Setelah menjalankan serangkaian pengujian, Anda dapat mengakses laporan cakupan pengujian yang menunjukkan evaluasi dari setiap aturan keamanan Anda.

Untuk mendapatkan laporan, buat kueri untuk endpoint yang terekspos pada emulator selagi endpoint ini berjalan. Untuk versi yang mudah digunakan di browser, gunakan URL berikut:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html

Proses ini memecah aturan Anda menjadi beberapa ekspresi dan subekspresi, dan Anda dapat mengarahkan kursor ke ekspresi/subekspresi tersebut untuk melihat informasinya lebih lanjut, termasuk jumlah evaluasi dan nilai yang dihasilkan. Untuk versi JSON mentah data ini, sertakan URL berikut dalam kueri Anda:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage

Perbedaan antara emulator dan produksi

  1. Anda tidak harus secara eksplisit membuat project Cloud Firestore. Emulator secara otomatis membuat setiap instance yang diakses.
  2. Emulator Cloud Firestore tidak berfungsi dengan alur Firebase Authentication normal. Sebagai gantinya, di Firebase Test SDK, kami telah menyediakan metode initializeTestApp() di library rules-unit-testing, yang menggunakan kolom auth. Handle Firebase yang dibuat menggunakan metode ini akan berperilaku seolah-olah telah berhasil diautentikasi sebagai entity apa pun yang Anda berikan. Jika Anda meneruskan null, objek tersebut akan berperilaku sebagai pengguna yang tidak diautentikasi (misalnya, aturan auth != null akan gagal).

Mengatasi masalah yang diketahui

Saat menggunakan emulator Cloud Firestore, Anda mungkin mengalami masalah yang diketahui di bawah ini. Ikuti panduan berikut untuk memecahkan masalah perilaku tidak teratur yang Anda alami. Catatan ini ditulis dengan Firebase Test SDK, tetapi pendekatan umum berlaku untuk setiap Firebase SDK.

Perilaku pengujian tidak konsisten

Jika pengujian Anda sesekali lulus dan gagal, bahkan tanpa perubahan apa pun pada pengujian itu sendiri, Anda mungkin perlu memastikan apakah pengujian ini telah diurutkan dengan benar atau belum. Sebagian besar interaksi dengan emulator bersifat asinkron, jadi periksa kembali apakah semua kode asinkron telah diurutkan dengan benar. Anda dapat memperbaiki urutan tersebut dengan menggabungkan promise atau menggunakan notasi await secara bebas.

Secara khusus, tinjau operasi asinkron berikut:

  • Menyetel aturan keamanan, dengan, misalnya, firebase.loadFirestoreRules.
  • Membaca dan menulis data, dengan, misalnya, db.collection("users").doc("alice").get().
  • Pernyataan operasional, termasuk firebase.assertSucceeds dan firebase.assertFails.

Pengujian hanya lulus saat pertama kali Anda memuat emulator

Emulator bersifat stateful. Emulator menyimpan semua data yang ditulis ke dalam memori, sehingga data apa pun akan hilang setiap kali emulator nonaktif. Jika Anda menjalankan beberapa pengujian terhadap project ID yang sama, setiap pengujian dapat menghasilkan data yang mungkin memengaruhi pengujian berikutnya. Anda dapat menggunakan salah satu metode berikut untuk mengabaikan perilaku ini:

  • Menggunakan project ID unik untuk setiap pengujian. Perhatikan bahwa jika Anda memilih untuk melakukan hal ini, Anda harus memanggil loadFirestoreRules sebagai bagian dari setiap pengujian; aturan hanya dimuat secara otomatis untuk project ID default.
  • Mengubah struktur pengujian Anda agar tidak berinteraksi dengan data tertulis sebelumnya (misalnya, gunakan koleksi yang berbeda untuk setiap pengujian).
  • Menghapus semua data yang ditulis selama pengujian.

Penyiapan pengujian sangat rumit

Anda dapat menguji skenario yang tidak diizinkan berdasarkan Aturan Keamanan Cloud Firestore Anda. Misalnya, sulit untuk menguji apakah pengguna yang tidak diautentikasi dapat mengedit data, karena Anda tidak dapat mengedit data sebagai pengguna yang tidak diautentikasi.

Jika aturan Anda memperumit penyiapan pengujian, coba gunakan klien yang diotorisasi admin untuk mengabaikan aturan. Anda dapat melakukannya dengan firebase.initializeAdminApp. Membaca dan menulis dari klien yang diotorisasi oleh admin mengabaikan aturan dan tidak memicu error PERMISSION_DENIED.