Podczas tworzenia aplikacji możesz zablokować dostęp do bazy danych Cloud Firestore. Przed uruchomieniem potrzebujesz bardziej szczegółowych reguł zabezpieczeń Cloud Firestore. Emulator Cloud Firestore pozwala nie tylko tworzyć prototypy i testować ogólne funkcje oraz działanie aplikacji, ale też pisać testy jednostkowe, które sprawdzają działanie reguł zabezpieczeń Cloud Firestore.
Krótkie wprowadzenie
Kilka podstawowych zastosowań testowych z prostymi regułami znajdziesz w krótkim wprowadzeniu.
Omówienie reguł zabezpieczeń Cloud Firestore
Gdy używasz bibliotek klienta mobilnego i internetowego, zaimplementuj Uwierzytelnianie Firebase i reguły zabezpieczeń Cloud Firestore, aby zapewnić bezserwerowe uwierzytelnianie, autoryzację i weryfikację danych.
Reguły zabezpieczeń Cloud Firestore składają się z 2 części:
- Instrukcja
match
identyfikująca dokumenty w bazie danych. - Wyrażenie
allow
kontrolujące dostęp do tych dokumentów.
Uwierzytelnianie Firebase weryfikuje dane logowania użytkowników oraz umożliwia tworzenie podstaw dla systemów dostępu opartych na użytkownikach i rolach.
Przed odczytaniem lub zapisem danych każde żądanie bazy danych z biblioteki klienta mobilnego/internetowego Cloud Firestore jest oceniane pod kątem reguł zabezpieczeń. Jeśli reguły odmówią dostępu do dowolnej z podanych ścieżek dokumentów, całe żądanie zakończy się niepowodzeniem.
Więcej informacji o regułach zabezpieczeń Cloud Firestore znajdziesz w artykule Pierwsze kroki z regułami zabezpieczeń Cloud Firestore.
Zainstaluj emulator
Aby zainstalować emulator Cloud Firestore, użyj interfejsu wiersza poleceń Firebase i uruchom to polecenie:
firebase setup:emulators:firestore
Uruchamianie emulatora
Zacznij od zainicjowania projektu Firebase w katalogu roboczym. Jest to typowy pierwszy krok podczas korzystania z interfejsu wiersza poleceń Firebase.
firebase init
Uruchom emulator za pomocą tego polecenia. Emulator będzie działać, dopóki nie zakończysz procesu:
firebase emulators:start --only firestore
Często trzeba uruchomić emulator, uruchomić pakiet testów, a potem wyłączyć emulator po przeprowadzeniu testów. Możesz to łatwo zrobić za pomocą polecenia emulators:exec
:
firebase emulators:exec --only firestore "./my-test-script.sh"
Po uruchomieniu emulator będzie próbował uruchomić się na porcie domyślnym (8080). Możesz zmienić port emulatora, modyfikując sekcję "emulators"
pliku firebase.json
:
{ // ... "emulators": { "firestore": { "port": "YOUR_PORT" } } }
Zanim uruchomisz emulator
Zanim zaczniesz korzystać z emulatora, pamiętaj o tych kwestiach:
- Emulator początkowo wczyta reguły określone w polu
firestore.rules
plikufirebase.json
. Oczekuje ona nazwy lokalnego pliku zawierającego reguły zabezpieczeń Cloud Firestore i stosuje te reguły do wszystkich projektów. Jeśli nie podasz lokalnej ścieżki pliku lub użyjesz metodyloadFirestoreRules
w sposób opisany poniżej, emulator potraktuje wszystkie projekty jako mające otwarte reguły. - Większość pakietów SDK Firebase współpracuje bezpośrednio z emulatorami, ale tylko biblioteka
@firebase/rules-unit-testing
obsługuje w regułach zabezpieczeń żarty zauth
, co znacznie ułatwia testowanie jednostkowe. Dodatkowo biblioteka obsługuje kilka funkcji specyficznych dla emulatorów, takich jak czyszczenie wszystkich danych wymienionych poniżej. - Emulatory będą też akceptować produkcyjne tokeny uwierzytelniania Firebase dostarczane za pomocą pakietów SDK klienta i odpowiednio oceniać reguły, co umożliwia bezpośrednie połączenie aplikacji z emulatorami w ramach testów integracji i testów ręcznych.
Przeprowadzanie lokalnych testów jednostkowych
Przeprowadzanie lokalnych testów jednostkowych za pomocą pakietu SDK JavaScript w wersji 9
Firebase rozpowszechnia bibliotekę testowania jednostkową reguł zabezpieczeń wraz z pakietem SDK JavaScript w wersji 9 oraz pakietem SDK w wersji 8. Interfejsy API bibliotek znacznie się różnią. Zalecamy korzystanie z biblioteki testowej w wersji 9, która jest bardziej usprawniona i wymaga mniej konfiguracji do łączenia się z emulatorami, dzięki czemu można bezpiecznie unikać przypadkowego użycia zasobów produkcyjnych. Aby zapewnić zgodność wsteczną, nadal udostępniamy bibliotekę do testowania wersji 8.
- Typowe metody testowania i funkcje narzędziowe w pakiecie SDK w wersji 9
- Metody testowe emulatorów w pakiecie SDK w wersji 9
Wykorzystaj moduł @firebase/rules-unit-testing
do interakcji z emulatorem, który działa lokalnie. Jeśli pojawią się błędy ECONNREFUSED
lub przekroczenie czasu oczekiwania, sprawdź, czy emulator faktycznie działa.
Zdecydowanie zalecamy korzystanie z najnowszej wersji środowiska Node.js, co umożliwi korzystanie z notacji async/await
. Prawie wszystkie działanie, które warto przetestować, obejmuje funkcje asynchroniczne, a moduł testowania został zaprojektowany do współpracy z kodem opartym na obietnicy.
Biblioteka testowania jednostkowego reguł w wersji 9 zawsze wie o emulatorach i nigdy nie ma wpływu na zasoby produkcyjne.
Bibliotekę zaimportujesz za pomocą modułowych instrukcji importowania w wersji 9. Przykład:
import {
assertFails,
assertSucceeds,
initializeTestEnvironment
} 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.
Po zaimportowaniu testy jednostkowe obejmują:
- Tworzę i konfiguruję
RulesTestEnvironment
z wywołanieminitializeTestEnvironment
. - Skonfigurowanie danych testowych bez uruchamiania reguł za pomocą wygodnej metody, która umożliwia tymczasowe ich ominięcie
RulesTestEnvironment.withSecurityRulesDisabled
. - Konfigurowanie pakietu testowego i punktów zaczepienia przed i po każdym teście z wywołaniami do oczyszczania danych i środowiska testowego, np.
RulesTestEnvironment.cleanup()
lubRulesTestEnvironment.clearFirestore()
. - Wdrażanie przypadków testowych imitujących stany uwierzytelniania za pomocą
RulesTestEnvironment.authenticatedContext
iRulesTestEnvironment.unauthenticatedContext
.
Typowe metody i funkcje użytkowe
Zobacz też metody testowe związane z emulatorami w pakiecie SDK w wersji 9.
initializeTestEnvironment() => RulesTestEnvironment
Ta funkcja inicjuje środowisko testowe do testowania jednostkowego reguł. Wywołaj tę funkcję najpierw na potrzeby konfiguracji testu. Udane wykonanie wymaga uruchomienia emulatorów.
Funkcja ta akceptuje opcjonalny obiekt definiujący TestEnvironmentConfig
, który może składać się z identyfikatora projektu i ustawień konfiguracji emulatora.
let testEnv = await initializeTestEnvironment({ projectId: "demo-project-1234", firestore: { rules: fs.readFileSync("firestore.rules", "utf8"), }, });
RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext
Ta metoda tworzy obiekt RulesTestContext
, który działa jak uwierzytelniony użytkownik uwierzytelniania. Do żądań utworzonych przy użyciu zwróconego kontekstu zostanie dołączony przykładowy token uwierzytelniania. Opcjonalnie możesz też przekazać obiekt definiujący deklaracje niestandardowe lub zastąpienia dla ładunków tokenów uwierzytelniania.
Aby uzyskać dostęp do wszystkich skonfigurowanych instancji emulatora, w tym tych skonfigurowanych przy użyciu initializeTestEnvironment
, użyj w testach zwróconego obiektu kontekstu testowego.
// 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
Ta metoda tworzy RulesTestContext
, który działa jak klient, który nie jest zalogowany za pomocą uwierzytelniania. Do żądań utworzonych przy użyciu zwróconego kontekstu nie będą dołączone tokeny uwierzytelniania Firebase.
Aby uzyskać dostęp do wszystkich skonfigurowanych instancji emulatora, w tym tych skonfigurowanych przy użyciu initializeTestEnvironment
, użyj w testach zwróconego obiektu kontekstu testowego.
// 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()
Uruchom funkcję konfiguracji testu w kontekście, który działa tak, jakby reguły zabezpieczeń były wyłączone.
Ta metoda korzysta z funkcji wywołania zwrotnego, która wykorzystuje kontekst pomijania reguł zabezpieczeń i zwraca obietnicę. Gdy obietnica zostanie spełniona lub odrzucona, kontekst zostanie zniszczony.
RulesTestEnvironment.cleanup()
Ta metoda niszczy wszystkie RulesTestContexts
utworzone w środowisku testowym i czyści bazowe zasoby, umożliwiając czyszczenie wyjścia.
Ta metoda nie zmienia w żaden sposób stanu emulatorów. Aby resetować dane między testami, użyj metody czyszczenia danych specyficznej dla emulatora aplikacji.
assertSucceeds(pr: Promise<any>)) => Promise<any>
To jest funkcja narzędziowa przypadku testowego.
Ta funkcja zapewnia, że podana operacja zawijania obietnic z emulatora zostanie zakończona bez naruszeń reguł zabezpieczeń.
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });
assertFails(pr: Promise<any>)) => Promise<any>
To jest funkcja narzędziowa przypadku testowego.
Ta funkcja zapewnia, że dostarczone działanie emulatora obietnicowe zostanie odrzucone z powodu naruszenia reguł zabezpieczeń.
await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });
Metody specyficzne dla emulatora
Zapoznaj się też z typowymi metodami testowania i funkcjami narzędziowymi w pakiecie SDK w wersji 9.
RulesTestEnvironment.clearFirestore() => Promise<void>
Ta metoda czyści w bazie danych Firestore dane należące do projectId
skonfigurowanego dla emulatora Firestore.
RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;
Ta metoda pobiera instancję Firestore na potrzeby tego kontekstu testowego. Zwróconej instancji pakietu SDK Firebase JS można używać z interfejsami API pakietu SDK klienta (modułowym w wersji 9 lub zgodnym z wersją 9).
Wizualizacja ocen reguł
Emulator Cloud Firestore umożliwia wizualizację żądań klientów w interfejsie pakietu emulatorów, w tym śledzenie ocen przez reguły zabezpieczeń Firebase.
Otwórz kartę Firestore > Żądania, aby wyświetlić szczegółową sekwencję oceny każdego żądania.
Generowanie raportów z testów
Po przeprowadzeniu zestawu testów możesz uzyskać dostęp do raportów o stanie testów, które pokazują, jak została oceniona każda z Twoich reguł zabezpieczeń.
Aby uzyskać te raporty, wyślij w emulatorze zapytanie do ujawnionego punktu końcowego, gdy jest on uruchomiony. W przypadku wersji przeznaczonej do wyświetlania w przeglądarce użyj tego adresu URL:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html
Spowoduje to podział reguł na wyrażenia i wyrażenia podrzędne, po których możesz najechać na nie kursorem, aby uzyskać więcej informacji, w tym liczbę ocen i zwróconych wartości. W przypadku nieprzetworzonej wersji JSON tych danych uwzględnij w zapytaniu ten adres URL:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage
Różnice między emulatorem a produkcją
- Nie musisz bezpośrednio tworzyć projektu Cloud Firestore. Emulator automatycznie tworzy każdą instancję, do której uzyskano dostęp.
- Emulator Cloud Firestore nie działa z zwykłym przepływem uwierzytelniania Firebase.
Zamiast tego w pakiecie SDK Firebase Test SDK w bibliotece
rules-unit-testing
udostępniliśmy metodęinitializeTestApp()
, która zajmuje poleauth
. Utworzony przy użyciu tej metody uchwyt Firebase będzie działać tak, jakby został pomyślnie uwierzytelniony jako dowolna podana przez Ciebie encja. Jeśli przekażesz zasadęnull
, będzie ona zachowywać się jak użytkownik nieuwierzytelniony (np. regułyauth != null
zakończą się niepowodzeniem).
Rozwiązywanie znanych problemów
Podczas korzystania z emulatora Cloud Firestore mogą wystąpić poniższe znane problemy. Aby rozwiązać problemy z nieregularnym zachowaniem, postępuj zgodnie z poniższymi wskazówkami. Zostały one pisane z myślą o bibliotece testowania jednostkowego reguł zabezpieczeń, ale ogólne podejścia mają zastosowanie do każdego pakietu SDK Firebase.
Działanie testu jest niespójne
Jeśli testy zaliczają się od czasu do czasu i kończą się niepowodzeniem, nawet jeśli nie wprowadzasz w nich żadnych zmian, sprawdź, czy są ustawione prawidłowo sekwencja.
Większość interakcji z emulatorem ma charakter asynchroniczny, więc upewnij się, że cały kod asynchroniczny jest poprawnie ułożony w kolejności. Możesz poprawić sekwencjonowanie, łącząc obietnice w łańcuchu lub swobodnie używając zapisu await
.
W szczególności sprawdź te operacje asynchroniczne:
- Ustawianie reguł zabezpieczeń, na przykład
initializeTestEnvironment
. - Odczyt i zapis danych, np.
db.collection("users").doc("alice").get()
. - Potwierdzenia działań, w tym
assertSucceeds
iassertFails
.
Testy zaliczają się tylko przy pierwszym wczytaniu emulatora
Emulator jest stanowy. Wszystkie zapisane w nim dane są przechowywane w pamięci, więc po wyłączeniu emulatora wszystkie dane są usuwane. Jeśli wykonujesz kilka testów z tym samym identyfikatorem projektu, każdy z nich może dostarczyć dane, które mogą mieć wpływ na kolejne testy. Aby obejść to zachowanie, możesz użyć dowolnej z tych metod:
- W każdym teście używaj unikalnych identyfikatorów projektów. Pamiętaj, że jeśli to zrobisz, w ramach każdego testu musisz wywołać metodę
initializeTestEnvironment
. Reguły będą ładowane automatycznie tylko w przypadku domyślnego identyfikatora projektu. - Zmień strukturę testów w taki sposób, aby nie wchodziły w interakcję z wcześniej zapisanymi danymi (np. użyj innej kolekcji w przypadku każdego testu).
- Usuń wszystkie dane zapisane podczas testu.
Konfiguracja testu jest bardzo skomplikowana
Podczas konfigurowania testu warto zmodyfikować dane w sposób, na który reguły zabezpieczeń Cloud Firestore nie zezwalają. Jeśli Twoje reguły sprawiają, że konfiguracja testu jest skomplikowana, spróbuj użyć w krokach konfiguracji funkcji RulesTestEnvironment.withSecurityRulesDisabled
, aby odczyty i zapisy nie wywołały błędów PERMISSION_DENIED
.
Po tym czasie test może wykonywać operacje jako uwierzytelniony lub nieuwierzytelniony użytkownik odpowiednio przy użyciu RulesTestEnvironment.authenticatedContext
i unauthenticatedContext
. Pozwala to sprawdzić, czy reguły zabezpieczeń Cloud Firestore prawidłowo zezwalają na poszczególne przypadki lub ich nie zezwalają.