Durante la creazione dell'app, potresti voler limitare l'accesso al tuo database Cloud Firestore. Tuttavia, prima del lancio, avrai bisogno di una strategia più Cloud Firestore Security Rules. Con l'emulatore Cloud Firestore, oltre a prototipare e testare le funzionalità e il comportamento generali della tua app, puoi scrivere unit test che controllano il comportamento del tuo Cloud Firestore Security Rules.
Guida rapida
Per alcuni casi di test di base con regole semplici, prova l'esempio di avvio rapido.
Comprendere Cloud Firestore Security Rules
Implementa Firebase Authentication e Cloud Firestore Security Rules per l'autenticazione, l'autorizzazione e la convalida dei dati serverless quando utilizzi le librerie client web e mobile.
Cloud Firestore Security Rules include due parti:
- Un'istruzione
match
che identifica i documenti nel tuo database. - Un'espressione
allow
che controlla l'accesso a questi documenti.
Firebase Authentication verifica le credenziali degli utenti e fornisce le basi per i sistemi di accesso basati su utenti e ruoli.
Ogni richiesta di database da una libreria client mobile/web Cloud Firestore viene valutata in base alle regole di sicurezza prima di leggere o scrivere dati. Se le regole negano l'accesso a uno dei percorsi dei documenti specificati, l'intera richiesta non va a buon fine.
Scopri di più su Cloud Firestore Security Rules in Inizia a utilizzare Cloud Firestore Security Rules.
Installare l'emulatore
Per installare l'emulatore Cloud Firestore, utilizza l'interfaccia a riga di comando Firebase ed esegui il comando riportato di seguito:
firebase setup:emulators:firestore
Esegui l'emulatore
Inizia inizializzando un progetto Firebase nella directory di lavoro. Questo è un primo passaggio comune quando si utilizza l'interfaccia a riga di comando di Firebase.
firebase init
Avvia l'emulatore utilizzando il seguente comando. L'emulatore verrà eseguito finché non interrompi il processo:
firebase emulators:start --only firestore
In molti casi, devi avviare l'emulatore, eseguire una suite di test e poi spegnerlo
dopo l'esecuzione dei test. Puoi farlo facilmente utilizzando il comando emulators:exec
:
firebase emulators:exec --only firestore "./my-test-script.sh"
Una volta avviato, l'emulatore tenterà di essere eseguito su una porta predefinita (8080). Puoi
modificare la porta dell'emulatore modificando la sezione "emulators"
del file
firebase.json
:
{ // ... "emulators": { "firestore": { "port": "YOUR_PORT" } } }
Prima di eseguire l'emulatore
Prima di iniziare a utilizzare l'emulatore, tieni presente quanto segue:
- L'emulatore caricherà inizialmente le regole specificate nel campo
firestore.rules
del filefirebase.json
. Si prevede il nome di un file locale contenente il tuo Cloud Firestore Security Rules e applica queste regole a tutti i progetti. Se non fornisci il percorso del file locale o non utilizzi il metodoloadFirestoreRules
come descritto di seguito, l'emulatore considera tutti i progetti come se avessero regole aperte. - Sebbene
la maggior parte degli SDK Firebase
funzioni direttamente con gli emulatori, solo la libreria
@firebase/rules-unit-testing
supporta la simulazioneauth
nelle regole di sicurezza, semplificando notevolmente i test unitari. Inoltre, la libreria supporta alcune funzionalità specifiche dell'emulatore, come la cancellazione di tutti i dati, come elencato di seguito. - Gli emulatori accettano anche i token di Firebase Auth di produzione forniti tramite gli SDK client e valutano le regole di conseguenza, il che consente di connettere l'applicazione direttamente agli emulatori nei test di integrazione e manuali.
Esegui test delle unità locali
Esegui test delle unità locali con l'SDK JavaScript v9
Firebase distribuisce una libreria di unit test delle regole di sicurezza sia con l'SDK JavaScript versione 9 sia con l'SDK versione 8. Le API della libreria sono molto diverse. Ti consigliamo la libreria di test v9, che è più snella e richiede meno configurazione per connettersi agli emulatori ed evitare così in modo sicuro l'uso accidentale di risorse di produzione. Per la compatibilità con le versioni precedenti, continuiamo a rendere disponibile la libreria di test v8.
- Metodi di test e funzioni di utilità comuni nell'SDK v9
- Metodi di test specifici dell'emulatore nell'SDK v9
Utilizza il modulo @firebase/rules-unit-testing
per interagire con l'emulatore
che viene eseguito localmente. Se si verificano timeout o errori ECONNREFUSED
, verifica
che l'emulatore sia effettivamente in esecuzione.
Ti consigliamo vivamente di utilizzare una versione recente di Node.js per poter utilizzare la notazione async/await
. Quasi tutto il comportamento che potresti voler testare
riguarda le funzioni asincrone e il modulo di test è progettato per funzionare con
il codice basato su promesse.
La libreria di test delle unità delle regole v9 è sempre a conoscenza degli emulatori e non tocca mai le risorse di produzione.
Importa la libreria utilizzando le istruzioni di importazione modulare v9. Ad esempio:
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.
Una volta importati, l'implementazione dei test delle unità prevede:
- Creazione e configurazione di un
RulesTestEnvironment
con una chiamata ainitializeTestEnvironment
. - Configurazione dei dati di test senza attivare le regole, utilizzando un metodo pratico che consente di aggirarle temporaneamente,
RulesTestEnvironment.withSecurityRulesDisabled
. - Configurazione della suite di test e degli hook pre/post test con chiamate per
pulire i dati e l'ambiente di test, ad esempio
RulesTestEnvironment.cleanup()
oRulesTestEnvironment.clearFirestore()
. - Implementazione di scenari di test che simulano gli stati di autenticazione utilizzando
RulesTestEnvironment.authenticatedContext
eRulesTestEnvironment.unauthenticatedContext
.
Metodi comuni e funzioni di utilità
Consulta anche Metodi di test specifici dell'emulatore nell'SDK v9.
initializeTestEnvironment() => RulesTestEnvironment
Questa funzione inizializza un ambiente di test per il test delle unità delle regole. Chiama questa funzione per prima per la configurazione del test. L'esecuzione corretta richiede l'esecuzione degli emulatori.
La funzione accetta un oggetto facoltativo che definisce un TestEnvironmentConfig
,
che può essere costituito da un ID progetto e dalle impostazioni di configurazione dell'emulatore.
let testEnv = await initializeTestEnvironment({ projectId: "demo-project-1234", firestore: { rules: fs.readFileSync("firestore.rules", "utf8"), }, });
RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext
Questo metodo crea un RulesTestContext
, che si comporta come un utente di autenticazione autenticato. Le richieste create tramite il contesto restituito avranno un token di autenticazione simulato allegato. (Facoltativo) Passa un oggetto che definisce rivendicazioni personalizzate o
override per i payload dei token di autenticazione.
Utilizza l'oggetto contesto di test restituito nei test per accedere a qualsiasi istanza dell'emulatore configurata, incluse quelle configurate con 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
Questo metodo crea un RulesTestContext
, che si comporta come un client che non ha eseguito l'accesso tramite autenticazione. Le richieste create tramite il contesto restituito non
avranno token Firebase Auth allegati.
Utilizza l'oggetto contesto di test restituito nei test per accedere a qualsiasi istanza dell'emulatore configurata, incluse quelle configurate con 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()
Esegui una funzione di configurazione del test con un contesto che si comporta come se le regole di sicurezza fossero disattivate.
Questo metodo accetta una funzione di callback, che accetta il contesto di bypass delle regole di sicurezza e restituisce una promessa. Il contesto verrà eliminato una volta che la promessa viene risolta / rifiutata.
RulesTestEnvironment.cleanup()
Questo metodo elimina tutti i RulesTestContexts
creati nell'ambiente di test e
pulisce le risorse sottostanti, consentendo un'uscita pulita.
Questo metodo non modifica in alcun modo lo stato degli emulatori. Per reimpostare i dati tra i test, utilizza il metodo di cancellazione dei dati specifico dell'emulatore dell'applicazione.
assertSucceeds(pr: Promise<any>)) => Promise<any>
Questa è una funzione di utilità per i casi di test.
La funzione asserisce che la promessa fornita che racchiude un'operazione dell'emulatore verrà risolta senza violazioni delle regole di sicurezza.
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });
assertFails(pr: Promise<any>)) => Promise<any>
Questa è una funzione di utilità per i casi di test.
La funzione asserisce che la promessa fornita che racchiude un'operazione dell'emulatore verrà rifiutata con una violazione delle regole di sicurezza.
await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });
Metodi specifici dell'emulatore
Consulta anche i metodi di test e le funzioni di utilità comuni nell'SDK v9.
RulesTestEnvironment.clearFirestore() => Promise<void>
Questo metodo cancella i dati nel database Firestore appartenenti al
projectId
configurato per l'emulatore Firestore.
RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;
Questo metodo recupera un'istanza di Firestore per questo contesto di test. L'istanza dell'SDK client Firebase JS restituita può essere utilizzata con le API dell'SDK client (modulare v9 o compatibilità v9).
Visualizzare le valutazioni delle regole
L'emulatore Cloud Firestore ti consente di visualizzare le richieste dei client nell'interfaccia utente di Emulator Suite, incluso il tracciamento della valutazione per le regole di sicurezza di Firebase.
Apri la scheda Firestore > Richieste per visualizzare la sequenza di valutazione dettagliata per ogni richiesta.
Generare report di test
Dopo aver eseguito una serie di test, puoi accedere ai report sulla copertura dei test che mostrano come è stata valutata ciascuna delle tue regole di sicurezza.
Per ottenere i report, esegui una query su un endpoint esposto nell'emulatore durante l'esecuzione. Per una versione compatibile con il browser, utilizza il seguente URL:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html
In questo modo, le regole vengono suddivise in espressioni e sottoespressioni su cui puoi passare il mouse per visualizzare ulteriori informazioni, tra cui il numero di valutazioni e i valori restituiti. Per la versione JSON non elaborata di questi dati, includi il seguente URL nella query:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage
Differenze tra l'emulatore e la produzione
- Non è necessario creare esplicitamente un progetto Cloud Firestore. L'emulatore crea automaticamente qualsiasi istanza a cui viene eseguito l'accesso.
- L'emulatore Cloud Firestore non funziona con il flusso normale Firebase Authentication.
Nell'SDK Firebase Test, invece, abbiamo fornito il metodo
initializeTestApp()
nella libreriarules-unit-testing
, che accetta un campoauth
. L'handle Firebase creato utilizzando questo metodo si comporterà come se l'autenticazione fosse andata a buon fine come qualsiasi entità tu fornisca. Se trasmettinull
, il comportamento sarà quello di un utente non autenticato (ad esempio, le regoleauth != null
non andranno a buon fine).
Risolvere i problemi noti
Durante l'utilizzo dell'emulatore Cloud Firestore, potresti riscontrare i seguenti problemi noti. Segui le indicazioni riportate di seguito per risolvere eventuali comportamenti anomali che stai riscontrando. Queste note sono scritte tenendo presente la libreria di unit test delle regole di sicurezza, ma gli approcci generali sono applicabili a qualsiasi SDK Firebase.
Il comportamento del test non è coerente
Se i test vengono superati e non superati occasionalmente, anche senza modifiche
ai test stessi, potrebbe essere necessario verificare che siano sequenziati correttamente.
La maggior parte delle interazioni con l'emulatore sono asincrone, quindi verifica che tutto
il codice asincrono sia sequenziato correttamente. Puoi correggere la sequenza concatenando le promesse o utilizzando liberamente la notazione await
.
In particolare, esamina le seguenti operazioni asincrone:
- Impostazione di regole di sicurezza, ad esempio con
initializeTestEnvironment
. - Lettura e scrittura dei dati, ad esempio con
db.collection("users").doc("alice").get()
. - Asserzioni operative, tra cui
assertSucceeds
eassertFails
.
I test vengono superati solo al primo caricamento dell'emulatore
L'emulatore è stateful. Memorizza tutti i dati scritti in memoria, quindi tutti i dati vengono persi ogni volta che l'emulatore si spegne. Se esegui più test sullo stesso ID progetto, ogni test può produrre dati che potrebbero influenzare i test successivi. Per aggirare questo comportamento, puoi utilizzare uno dei seguenti metodi:
- Utilizza ID progetto univoci per ogni test. Tieni presente che se scegli di farlo,
dovrai chiamare
initializeTestEnvironment
come parte di ogni test; le regole vengono caricate automaticamente solo per l'ID progetto predefinito. - Ristruttura i test in modo che non interagiscano con i dati scritti in precedenza (ad esempio, utilizza una raccolta diversa per ogni test).
- Elimina tutti i dati scritti durante un test.
La configurazione del test è molto complicata
Quando configuri il test, potresti voler modificare i dati in un modo che i tuoi
Cloud Firestore Security Rules non consentono. Se le regole rendono complessa la configurazione del test, prova a utilizzare RulesTestEnvironment.withSecurityRulesDisabled
nei passaggi di configurazione, in modo che le letture e le scritture non attivino errori PERMISSION_DENIED
.
Dopodiché, il test può eseguire operazioni come utente autenticato o non autenticato
utilizzando rispettivamente RulesTestEnvironment.authenticatedContext
e unauthenticatedContext
. In questo modo puoi verificare che il tuo Cloud Firestore Security Rules consenta / neghi
correttamente i diversi casi.