Podczas tworzenia aplikacji możesz chcieć zablokować dostęp do bazy danych Cloud Firestore. Zanim jednak to zrobisz, musisz dowiedzieć się więcej o tym, jak Cloud Firestore Security Rules. W emulatorze Cloud Firestore możesz nie tylko tworzyć prototypy i testować ogólne funkcje i zachowanie aplikacji, ale też pisać testy jednostkowe, które sprawdzają zachowanie Cloud Firestore Security Rules.
Krótkie wprowadzenie
Aby zobaczyć kilka podstawowych przypadków testowych z prostymi regułami, skorzystaj z przykładu szybkiego startu.
Cloud Firestore Security Rules
W przypadku korzystania z bibliotek klienta na urządzenia mobilne i w internecie należy zaimplementować Firebase Authentication i Cloud Firestore Security Rules do uwierzytelniania bez serwera, autoryzacji i weryfikacji danych.
Cloud Firestore Security Rules składają się z 2 elementów:
match
, który identyfikuje dokumenty w Twojej bazie danych.allow
wyrażenie kontrolujące dostęp do tych dokumentów.
Firebase Authentication weryfikuje dane logowania użytkowników i stanowi podstawę systemów dostępu opartych na użytkownikach i rolach.
Każde żądanie bazy danych z biblioteki klienta mobilnego/internetowego Cloud Firestore jest sprawdzane pod kątem zgodności z regułami zabezpieczeń przed odczytaniem lub zapisaniem jakichkolwiek danych. Jeśli reguły odmawiają dostępu do dowolnej ze ścieżek dokumentów, cała prośba kończy się niepowodzeniem.
Więcej informacji o programie Cloud Firestore Security Rules znajdziesz w artykule Pierwsze kroki z Cloud Firestore Security Rules.
Instalowanie emulatora
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 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
W wielu przypadkach należy uruchomić emulator, uruchomić zestaw testów, a potem zamknąć emulator po zakończeniu testów. Możesz to łatwo zrobić za pomocą polecenia emulators:exec
:
firebase emulators:exec --only firestore "./my-test-script.sh"
Po uruchomieniu emulator spróbuje uruchomić się na domyślnym porcie (8080). Możesz zmienić port emulatora, modyfikując sekcję "emulators"
w pliku firebase.json
:
{ // ... "emulators": { "firestore": { "port": "YOUR_PORT" } } }
Przed uruchomieniem emulatora
Zanim zaczniesz korzystać z emulatora, pamiętaj o tych kwestiach:
- Na początku emulator wczyta reguły określone w polu
firestore.rules
plikufirebase.json
. Wymaga ona podania nazwy pliku lokalnego zawierającego reguły Cloud Firestore Security Rules i zastosowuje te reguły do wszystkich projektów. Jeśli nie podasz ścieżki do pliku lokalnego ani nie użyjesz metodyloadFirestoreRules
opisanej poniżej, emulator będzie traktować wszystkie projekty jako mające otwarte reguły. - Chociaż większości pakietów SDK Firebase można używać bezpośrednio z emulatorami, tylko biblioteka
@firebase/rules-unit-testing
obsługuje symulowanieauth
w regułach zabezpieczeń, co znacznie ułatwia testy jednostkowe. Dodatkowo biblioteka obsługuje kilka funkcji związanych z konkretnym emulatorem, takich jak czyszczenie wszystkich danych, które wymieniono poniżej. - Emulatorów można też używać do testowania integracji i ręcznych testów, łącząc aplikację bezpośrednio z emulatorami. W tym celu emulatory będą akceptować tokeny uwierzytelniania Firebase w wersji produkcyjnej udostępniane za pomocą pakietów SDK klienta i odpowiednio oceniać reguły.
Wykonywanie testów jednostkowych na komputerze lokalnym
Uruchom testy jednostkowe na komputerze za pomocą pakietu SDK JavaScript w wersji 9
Firebase udostępnia bibliotekę do testowania jednostek reguł bezpieczeństwa zarówno z pakietem SDK JavaScript w wersji 9, jak i z pakietem SDK w wersji 8. Interfejsy API bibliotek są znacznie inne. Zalecamy bibliotekę testów v9, która jest bardziej uproszczona i wymaga mniej konfiguracji do połączenia z emulatorami, dzięki czemu można bezpiecznie uniknąć przypadkowego użycia zasobów produkcyjnych. Ze względu na zgodność wsteczną nadal udostępniamy bibliotekę testów w wersji 8.
- Najczęściej używane metody testów i funkcje pomocnicze w pakiecie SDK w wersji 9
- Metody testów w emulatorze w pakiecie SDK w wersji 9
Użyj modułu @firebase/rules-unit-testing
, aby wchodzić w interakcje z emulatorem działającym lokalnie. Jeśli wystąpią przekroczenia limitu czasu lub błędy ECONNREFUSED
, sprawdź, czy emulator rzeczywiście działa.
Zdecydowanie zalecamy korzystanie z najnowszej wersji Node.js, aby można było używać notacji async/await
. Prawie wszystkie zachowania, które chcesz przetestować, obejmują funkcje asynchroniczne, a moduł testowania jest zaprojektowany do współpracy z kodem opartym na obietnicach.
Biblioteka testowania jednostkowego reguł v9 jest zawsze świadoma emulatorów i nigdy nie dotyka Twoich zasobów produkcyjnych.
Bibliotekę importujesz za pomocą instrukcji importu modułowego v9. 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 testów jednostkowych należy:
- Tworzenie i konfigurowanie
RulesTestEnvironment
za pomocą wywołania funkcjiinitializeTestEnvironment
. - Konfigurowanie danych testowych bez uruchamiania reguł za pomocą wygodnej metody, która pozwala na ich tymczasowe pominięcie:
RulesTestEnvironment.withSecurityRulesDisabled
. - Konfigurowanie zestawu testów i funkcji przed testem lub po nim za pomocą wywołań służących do czyszczenia danych testowych i środowiska, takich jak
RulesTestEnvironment.cleanup()
lubRulesTestEnvironment.clearFirestore()
. - Wdrażanie przypadków testowych, które symulują stany uwierzytelniania za pomocą
RulesTestEnvironment.authenticatedContext
iRulesTestEnvironment.unauthenticatedContext
.
Typowe metody i funkcje użyteczności
Zobacz też metody testów w emulatorze w pakiecie SDK w wersji 9.
initializeTestEnvironment() => RulesTestEnvironment
Ta funkcja inicjuje środowisko testowe do testowania reguł jednostkowych. Aby skonfigurować test, najpierw wywołaj tę funkcję. Aby uruchomić test, musisz uruchomić emulatory.
Funkcja akceptuje opcjonalny obiekt definiujący TestEnvironmentConfig
, który może zawierać identyfikator projektu i ustawienia 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 zachowuje się jak uwierzytelniony użytkownik. Żądania utworzone za pomocą zwróconego kontekstu będą zawierać dołączony fałszywy token uwierzytelniający. Opcjonalnie prześlij obiekt definiujący roszczenia niestandardowe lub zastąpienia dla danych tokena uwierzytelniania.
Używaj zwracanego obiektu test context w testach, aby uzyskać dostęp do skonfigurowanych instancji emulatora, w tym do tych skonfigurowanych za pomocą 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
Ta metoda tworzy RulesTestContext
, który zachowuje się jak klient, który nie zalogował się za pomocą uwierzytelniania. Żądania utworzone za pomocą zwróconego kontekstu nie będą zawierać tokenów Uwierzytelniania Firebase.
Używaj zwracanego obiektu test context w testach, aby uzyskać dostęp do skonfigurowanych instancji emulatora, w tym do tych skonfigurowanych za pomocą 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()
Uruchom funkcję testowego ustawienia z kontekstem, który zachowuje się tak, jakby reguły zabezpieczeń były wyłączone.
Ta metoda przyjmuje funkcję wywołania zwrotnego, która przyjmuje kontekst pomijania reguł bezpieczeństwa i zwraca obietnicę. Kontekst zostanie usunięty, gdy obietnica zostanie spełniona lub odrzucona.
RulesTestEnvironment.cleanup()
Ta metoda usuwa wszystkie RulesTestContexts
utworzone w środowisku testowym i oczyszcza zasoby, co umożliwia prawidłowe zakończenie.
Ta metoda nie zmienia w żaden sposób stanu emulatorów. Aby zresetować dane między testami, użyj metody czyszczenia danych odpowiedniej dla danego emulatora aplikacji.
assertSucceeds(pr: Promise<any>)) => Promise<any>
To jest funkcja pomocnicza testowego przypadku użycia.
Funkcja stwierdza, że dostarczona obietnica obejmująca operację emulatora zostanie rozwiązana bez naruszenia reguł zabezpieczeń.
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });
assertFails(pr: Promise<any>)) => Promise<any>
To jest funkcja pomocnicza testowego przypadku użycia.
Funkcja stwierdza, że dostarczona obietnica obejmująca działanie emulatora zostanie odrzucona z powodu naruszenia reguł bezpieczeństwa.
await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });
Metody dotyczące emulatora
Zobacz też popularne metody testowania i funkcje pomocnicze w pakiecie SDK w wersji 9.
RulesTestEnvironment.clearFirestore() => Promise<void>
Ta metoda usuwa dane z bazy danych Firestore należącej do instancji projectId
skonfigurowanej dla emulatora Firestore.
RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;
Ta metoda pobiera instancję Firestore dla tego testowanego kontekstu. Zwrócony obiekt pakietu SDK klienta Firebase JS można używać z interfejsami API pakietu SDK klienta (wersja 9 modularna lub kompatybilna z wersją 9).
Wizualizacja oceny reguł
Emulator Cloud Firestore umożliwia wizualizację żądań klientów w interfejsie Pakietu emulatorów, w tym śledzenie oceny reguł zabezpieczeń Firebase.
Aby wyświetlić szczegółową sekwencję oceny dla każdej prośby, otwórz kartę Firestore > Prośby.
Generowanie raportów testowych
Po uruchomieniu zestawu testów możesz uzyskać dostęp do raportów o zakresie testów, które pokazują, jak oceniono każdą z reguł bezpieczeństwa.
Aby uzyskać raporty, prześlij zapytanie do punktu końcowego w emulatorze, gdy jest on uruchomiony. Aby uzyskać wersję przyjazną przeglądarce, użyj tego adresu URL:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html
Dzięki temu reguły są dzielone na wyrażenia i podwyrażenia, nad którymi możesz najechać kursorem, aby uzyskać więcej informacji, w tym liczbę zwracanych ocen i wartości. Aby uzyskać wersję tych danych w postaci surowego pliku JSON, dodaj do zapytania ten adres URL:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage
Różnice między emulatorem a wersją produkcyjną
- Nie musisz tworzyć projektu Cloud Firestore. Emulator automatycznie tworzy każdą instancję, do której uzyskuje dostęp.
- Emulator Cloud Firestore nie działa w ramach normalnego przepływu danych Firebase Authentication.
Zamiast tego w pakiecie Firebase Test SDK udostępniliśmy w bibliotece
rules-unit-testing
metodęinitializeTestApp()
, która przyjmuje poleauth
. Element Firebase utworzony za pomocą tej metody będzie się zachowywać tak, jakby został uwierzytelniony jako dowolny podany przez Ciebie podmiot. Jeśli przekażesz wartośćnull
, będzie ona zachowywać się jak niezalogowany użytkownik (np. regułyauth != null
nie będą działać).
Rozwiązywanie znanych problemów
Podczas korzystania z emulatora Cloud Firestore możesz napotkać te znane problemy. Aby rozwiązać problemy z nieprawidłowym działaniem, postępuj zgodnie z instrukcjami poniżej. Te uwagi dotyczą testowania jednostkowego biblioteki reguł zabezpieczeń, ale ogólne podejścia można stosować do dowolnego pakietu Firebase SDK.
Zachowanie testu jest niespójne
Jeśli testy są czasem zaliczane, a czasem nie, nawet bez wprowadzania zmian w samych testach, konieczne może być sprawdzenie, czy są one prawidłowo uporządkowane.
Większość interakcji z emulatorem jest asynchroniczna, więc sprawdź, czy cały kod asynchroniczny jest poprawnie uporządkowany. Możesz poprawić kolejność, łącząc obie obietnice lub stosując notację await
.
Zwróć szczególną uwagę na te operacje asynchroniczne:
- Ustawianie reguł zabezpieczeń, na przykład
initializeTestEnvironment
. - odczytywanie i zapisywanie danych, na przykład
db.collection("users").doc("alice").get()
. - oświadczenia operacyjne, w tym
assertSucceeds
iassertFails
;
Testy przechodzą tylko przy pierwszym uruchomieniu emulatora.
Emulator jest stanowy. Przechowuje wszystkie dane zapisane w pamięci, więc podczas zamykania emulatora nie ma utraty danych. Jeśli przeprowadzasz wiele testów dotyczących tego samego identyfikatora projektu, każdy z nich może wygenerować dane, które mogą wpływać na kolejne testy. Aby ominąć to zachowanie, możesz użyć dowolnej z tych metod:
- Używaj unikalnych identyfikatorów projektów w przypadku każdego testu. Jeśli zdecydujesz się na to, musisz wywołać funkcję
initializeTestEnvironment
w ramach każdego testu. Reguły są automatycznie wczytywane tylko w przypadku domyślnego identyfikatora projektu. - Zmień strukturę testów, aby nie oddziaływały na wcześniej zapisane dane (np. używaj innej kolekcji dla każdego testu).
- usunąć wszystkie dane zapisane podczas testu.
Konfiguracja testu jest bardzo skomplikowana
Podczas konfigurowania testu możesz chcieć zmodyfikować dane w sposób, który nie jest obsługiwany przez Cloud Firestore Security Rules. Jeśli Twoje reguły powodują, że konfiguracja testu jest skomplikowana, spróbuj użyć RulesTestEnvironment.withSecurityRulesDisabled
w krokach konfiguracji, aby odczyty i zapisy nie powodowały błędów PERMISSION_DENIED
.
Następnie test może wykonywać operacje jako uwierzytelniony lub niezautentifikowany użytkownik, odpowiednio za pomocą funkcji RulesTestEnvironment.authenticatedContext
lub unauthenticatedContext
. Dzięki temu możesz sprawdzić, czy Cloud Firestore Security Rules poprawnie zezwala na dostęp lub odmawia go w różnych przypadkach.