Podczas tworzenia aplikacji możesz zablokować dostęp do swojej Cloud Firestore bazy danych. Zanim jednak opublikujesz aplikację, musisz mieć bardziej szczegółowe Cloud Firestore Security Rules. Za pomocą emulatora Cloud Firestore możesz nie tylko tworzyć prototypy i testować ogólne funkcje i zachowanie aplikacji, ale też pisać testy jednostkowe, które sprawdzają działanie Cloud Firestore Security Rules.
Krótkie wprowadzenie
Aby zapoznać się z kilkoma podstawowymi przypadkami testowymi z prostymi regułami, wypróbuj przykład z krótkiego wprowadzenia.
Omówienie Cloud Firestore Security Rules
Wdrażaj Firebase Authentication i Cloud Firestore Security Rules na potrzeby uwierzytelniania, autoryzacji i weryfikacji danych bezserwerowych, gdy używasz bibliotek klienta mobilnego i internetowego.
Cloud Firestore Security Rules obejmują 2 elementy:
- Instrukcja
match, która identyfikuje dokumenty w bazie danych. - Wyrażenie
allow, które kontroluje 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 lub internetowego Cloud Firestore jest oceniane na podstawie reguł zabezpieczeń przed odczytaniem lub zapisaniem danych. Jeśli reguły odmawiają dostępu do którejkolwiek z określonych ścieżek dokumentów, całe żądanie kończy się niepowodzeniem.
Więcej informacji o Cloud Firestore Security Rules znajdziesz w artykule Wprowadzenie do Cloud Firestore Security Rules.
Instalowanie emulatora
Aby zainstalować emulator Cloud Firestore, użyj wiersza poleceń Firebase CLI i uruchom to polecenie:
firebase setup:emulators:firestore
Uruchamianie emulatora
Zacznij od zainicjowania projektu w 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 chcesz uruchomić emulator, przeprowadzić zestaw testów, a następnie zamknąć go 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 będzie próbował działać na porcie domyślnym (8080). Port emulatora możesz
zmienić, modyfikując sekcję "emulators" w pliku
firebase.json file:
{
// ...
"emulators": {
"firestore": {
"port": "YOUR_PORT"
}
}
}Przed uruchomieniem emulatora
Zanim zaczniesz korzystać z emulatora, pamiętaj o tych kwestiach:
- Emulator początkowo wczyta reguły określone w polu
firestore.rulesw plikufirebase.json. Oczekuje on nazwy pliku lokalnego zawierającego Cloud Firestore Security Rules i stosuje te reguły do wszystkich projektów. Jeśli nie podasz ścieżki do pliku lokalnego lub nie użyjesz metodyloadFirestoreRulesopisanej poniżej, emulator będzie traktować wszystkie projekty jako mające otwarte reguły. - Chociaż
większość pakietów SDK Firebase
działa bezpośrednio z emulatorami, tylko biblioteka
@firebase/rules-unit-testingobsługuje tworzenie kopii zapasowychauthw regułach zabezpieczeń, co znacznie ułatwia testy jednostkowe. Dodatkowo biblioteka obsługuje kilka funkcji specyficznych dla emulatora, takich jak czyszczenie wszystkich danych, które są wymienione poniżej. - Emulatory będą też akceptować tokeny uwierzytelniania Firebase w wersji produkcyjnej dostarczane przez pakiety SDK klienta i odpowiednio oceniać reguły, co umożliwia bezpośrednie połączenie aplikacji z emulatorami w testach integracyjnych i ręcznych.
Uruchamianie lokalnych testów jednostkowych
Uruchamianie lokalnych testów jednostkowych za pomocą pakietu JavaScript SDK w wersji 9
Firebase udostępnia bibliotekę testów jednostkowych reguł zabezpieczeń zarówno w pakiecie JavaScript SDK w wersji 9, jak i w wersji 8. Interfejsy API biblioteki znacznie się różnią. Zalecamy korzystanie z biblioteki testowej w wersji 9, która jest bardziej uproszczona i wymaga mniej konfiguracji, aby połączyć się z emulatorami, a tym samym bezpiecznie uniknąć przypadkowego użycia zasobów produkcyjnych. Aby zapewnić wsteczną zgodność, nadal udostępniamy bibliotekę testową w wersji 8.
- Typowe metody testowe i funkcje narzędziowe w pakiecie SDK w wersji 9
- Metody testowe specyficzne dla emulatora 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 pojawią się przekroczenia limitu czasu lub błędy ECONNREFUSED, sprawdź, czy emulator rzeczywiście działa.
Zdecydowanie zalecamy używanie najnowszej wersji Node.js, aby móc korzystać z notacji async/await. Prawie wszystkie zachowania, które możesz chcieć przetestować, obejmują funkcje asynchroniczne, a moduł testowy jest przeznaczony do pracy z kodem opartym na obietnicach.
Biblioteka testów jednostkowych reguł w wersji 9 zawsze wie o emulatorach i nigdy nie dotyka zasobów produkcyjnych.
Bibliotekę importujesz za pomocą instrukcji importu modułowego 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 implementacja testów jednostkowych obejmuje:
- Utworzenie i skonfigurowanie
RulesTestEnvironmentza pomocą wywołaniainitializeTestEnvironment. - Konfigurowanie danych testowych bez wywoływania reguł za pomocą wygodnej metody, która umożliwia tymczasowe ich pominięcie,
RulesTestEnvironment.withSecurityRulesDisabled. - Konfigurowanie zestawu testów i haków przed/po teście za pomocą wywołań zwalniania miejsca na dane testowe i środowisko, takich jak
RulesTestEnvironment.cleanup()lubRulesTestEnvironment.clearFirestore(). - Implementowanie przypadków testowych, które naśladują stany uwierzytelniania, za pomocą
RulesTestEnvironment.authenticatedContextiRulesTestEnvironment.unauthenticatedContext.
Typowe metody i funkcje narzędziowe
Zobacz też metody testowe specyficzne dla emulatora w pakiecie SDK w wersji 9.
initializeTestEnvironment() => RulesTestEnvironment
Ta funkcja inicjuje środowisko testowe na potrzeby testów jednostkowych reguł. Wywołaj tę funkcję jako pierwszą w konfiguracji testu. Aby wykonanie się powiodło, emulatory muszą być uruchomione.
Funkcja 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 RulesTestContext, który zachowuje się jak uwierzytelniony użytkownik uwierzytelniania. Żądania utworzone za pomocą zwróconego kontekstu będą miały dołączony token uwierzytelniania. Opcjonalnie możesz przekazać obiekt definiujący niestandardowe deklaracje lub zastąpienia ładunków tokena uwierzytelniania.
Użyj zwróconego obiektu kontekstu testowego w testach, aby uzyskać dostęp do wszystkich skonfigurowanych instancji emulatora, w tym 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().doc('/users/alice'), { ... });
RulesTestEnvironment.unauthenticatedContext() => RulesTestContext
Ta metoda tworzy RulesTestContext, który zachowuje się jak klient niezalogowany za pomocą uwierzytelniania. Żądania utworzone za pomocą zwróconego kontekstu nie będą miały dołączonych tokenów uwierzytelniania Firebase.
Użyj zwróconego obiektu kontekstu testowego w testach, aby uzyskać dostęp do wszystkich skonfigurowanych instancji emulatora, w tym 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ę konfiguracji testu 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 pomijający reguły zabezpieczeń i zwraca obietnicę. Kontekst zostanie zniszczony po rozwiązaniu lub odrzuceniu obietnicy.
RulesTestEnvironment.cleanup()
Ta metoda niszczy wszystkie RulesTestContexts utworzone w środowisku testowym i czyści zasoby bazowe, co umożliwia czyste wyjście.
Ta metoda w żaden sposób nie zmienia stanu emulatorów. Aby zresetować dane między testami, użyj metody czyszczenia danych specyficznej dla emulatora aplikacji.
assertSucceeds(pr: Promise<any>)) => Promise<any>
To funkcja użytkowa przypadku testowego.
Funkcja sprawdza, czy podana obietnica opakowująca operację emulatora zostanie rozwiązana bez naruszenia reguł zabezpieczeń.
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });assertFails(pr: Promise<any>)) => Promise<any>
To funkcja użytkowa przypadku testowego.
Funkcja sprawdza, czy podana obietnica opakowująca operację emulatora zostanie odrzucona z powodu naruszenia reguł zabezpieczeń.
await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });Metody specyficzne dla emulatora
Zobacz też typowe metody testowe i funkcje narzędziowe w pakiecie SDK w wersji 9.
RulesTestEnvironment.clearFirestore() => Promise<void>
Ta metoda czyści dane w bazie danych Firestore, które należą do projectId skonfigurowanego dla emulatora Firestore.
RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;
Ta metoda pobiera instancję Firestore dla tego kontekstu testowego. Zwróconą instancję pakietu Firebase JS Client SDK można używać z interfejsami API pakietu SDK klienta (modułowego w wersji 9 lub zgodnego w wersji 9).
Wizualizowanie ocen reguł
Emulator Cloud Firestore umożliwia wizualizowanie żądań klientów w interfejsie pakietu emulatorów, w tym śledzenie ocen reguł zabezpieczeń Firebase.
Otwórz kartę Firestore > Żądania, aby wyświetlić szczegółową sekwencję ocen dla każdego żądania.
Generowanie raportów testowych
Po przeprowadzeniu zestawu testów możesz uzyskać dostęp do raportów pokrycia testami, które pokazują, jak oceniana była każda z reguł zabezpieczeń.
Aby uzyskać raporty, wyślij zapytanie do udostępnionego punktu końcowego w działającym emulatorze. Aby uzyskać wersję przyjazną dla przeglądarki, użyj tego adresu URL:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html
Dzieli to reguły na wyrażenia i podwyrażenia, nad którymi możesz najechać kursorem, aby uzyskać więcej informacji, w tym liczbę ocen i zwrócone wartości. Aby uzyskać wersję tych danych w formacie 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 wyraźnie tworzyć projektu Cloud Firestore. Emulator automatycznie tworzy każdą instancję, do której uzyskuje się dostęp.
- Emulator Cloud Firestore nie działa ze standardowym przepływem Firebase Authentication.
Zamiast tego w pakiecie Firebase Test SDK udostępniliśmy metodę
initializeTestApp()w bibliotecerules-unit-testing, która przyjmuje poleauth. Uchwyt Firebase utworzony za pomocą tej metody będzie się zachowywać tak, jakby został pomyślnie uwierzytelniony jako podmiot, który podasz. Jeśli przekażesz wartośćnull, będzie się zachowywać jak nieuwierzytelniony użytkownik (auth != nullreguły zakończą się niepowodzeniem, na przykład).
Rozwiązywanie znanych problemów
Podczas korzystania z emulatora Cloud Firestore możesz napotkać te znane problemy. Aby rozwiązać wszelkie nieprawidłowe zachowania, postępuj zgodnie z poniższymi wskazówkami. Te uwagi zostały napisane z myślą o bibliotece testów jednostkowych reguł zabezpieczeń, ale ogólne podejścia mają zastosowanie do każdego pakietu SDK Firebase.
Niespójne zachowanie testów
Jeśli testy czasami przechodzą, a czasami nie, nawet bez wprowadzania zmian w samych testach, może być konieczne sprawdzenie, czy są one prawidłowo uporządkowane.
Większość interakcji z emulatorem jest asynchroniczna, dlatego sprawdź, czy cały kod asynchroniczny jest prawidłowo uporządkowany. Kolejność możesz poprawić, łącząc obietnice lub używając notacji await.
W szczególności sprawdź te operacje asynchroniczne:
- Ustawianie reguł zabezpieczeń, np. za pomocą
initializeTestEnvironment. - Odczytywanie i zapisywanie danych, np. za pomocą
db.collection("users").doc("alice").get(). - Asercje operacyjne, w tym
assertSucceedsiassertFails.
Testy przechodzą tylko przy pierwszym wczytaniu emulatora
Emulator jest stanowy. Przechowuje wszystkie zapisane w nim dane w pamięci, więc wszystkie dane są tracone po zamknięciu emulatora. Jeśli uruchamiasz wiele testów na tym samym identyfikatorze projektu, każdy test może generować dane, które mogą wpływać na kolejne testy. Aby pominąć to zachowanie, możesz użyć jednej z tych metod:
- Używaj unikalnych identyfikatorów projektów dla każdego testu. Pamiętaj, że jeśli to zrobisz, musisz wywołać
initializeTestEnvironmentw ramach każdego testu. Reguły są automatycznie wczytywane tylko w przypadku domyślnego identyfikatora projektu. - Zmień strukturę testów tak, aby nie wchodziły w interakcje z wcześniej zapisanymi danymi (np. używaj innej kolekcji dla każdego testu).
- Usuń wszystkie dane zapisane podczas testu.
Konfiguracja testu jest bardzo skomplikowana
Podczas konfigurowania testu możesz chcieć zmodyfikować dane w sposób, który Twoje
Cloud Firestore Security Rules nie są dozwolone. Jeśli reguły utrudniają konfigurację testu, 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 nieuwierzytelniony użytkownik, używając odpowiednio RulesTestEnvironment.authenticatedContext i unauthenticatedContext. Umożliwia to sprawdzenie, czy reguły zabezpieczeń Cloud Firestore prawidłowo zezwalają na różne przypadki lub odmawiają dostępu.Cloud Firestore Security Rules