Recomendamos que bloquees el acceso a la base de datos de Cloud Firestore a medida que compiles tu app. Sin embargo, antes de que la inicies, deberás contar con reglas de seguridad de Cloud Firestore más avanzadas. Con el emulador de Cloud Firestore, además de probar las funciones y el comportamiento generales de tu app y crear prototipos de ellos, puedes escribir pruebas de unidades que verifiquen el comportamiento de tus reglas de seguridad de Cloud Firestore.
Guía de inicio rápido
Si quieres consultar algunos casos de prueba con reglas simples, usa la guía de inicio rápido de ejemplo.
Comprende las reglas de seguridad de Cloud Firestore
Implementa Firebase Authentication y las reglas de seguridad de Cloud Firestore para la autenticación, autorización y validación de datos sin servidores cuando uses las bibliotecas cliente para dispositivos móviles y la Web.
Las reglas de seguridad de Cloud Firestore incluyen dos partes:
- Una declaración
match
que identifica los documentos en tu base de datos - Una expresión
allow
que controla el acceso a los documentos
Firebase Authentication verifica las credenciales de los usuarios y proporciona una base para los sistemas de acceso basados en usuarios y funciones.
Todas las solicitudes que se envíen a la base de datos desde una biblioteca cliente de Cloud Firestore web o para dispositivos móviles se comparan con tus reglas de seguridad antes de poder leer o escribir datos. Si las reglas rechazan el acceso a alguna de las rutas de los documentos especificados, falla la solicitud completa.
Obtén más información sobre las reglas de seguridad de Cloud Firestore en Cómo comenzar con las reglas de seguridad de Cloud Firestore.
Instala el emulador
Para instalar el emulador de Cloud Firestore, usa Firebase CLI y ejecuta el comando que aparece a continuación:
firebase setup:emulators:firestore
Ejecuta el emulador
Comienza por inicializar un proyecto de Firebase en el directorio de trabajo. Este es un primer paso habitual cuando se usa Firebase CLI.
firebase init
Inicia el emulador con el siguiente comando. El emulador se ejecutará hasta que finalices el proceso:
firebase emulators:start --only firestore
En muchos casos, es recomendable que inicies el emulador, ejecutes una prueba y, luego, cierres el emulador después de que hayas ejecutado las pruebas. Puedes hacerlo de manera sencilla con el comando emulators:exec
, como en el ejemplo:
firebase emulators:exec --only firestore "./my-test-script.sh"
Cuando se inicie, el emulador intentará ejecutarse en un puerto predeterminado (8080). Para cambiar el puerto del emulador, modifica la sección "emulators"
del archivo firebase.json
:
{ // ... "emulators": { "firestore": { "port": "YOUR_PORT" } } }
Antes de que ejecutes el emulador
Antes de comenzar a usar el emulador, ten en cuenta lo siguiente:
- Inicialmente, el emulador cargará las reglas especificadas en el campo
firestore.rules
de tu archivofirebase.json
. Este espera el nombre de un archivo local con tus reglas de seguridad de Cloud Firestore y las aplica a todos los proyectos. Si no proporcionas la ruta de un archivo local o no usas el métodoloadFirestoreRules
como se describe a continuación, el emulador trata todos los proyectos como si tuvieran reglas abiertas. - Si bien la mayoría de los SDK de Firebase funcionan con los emuladores de forma directa, solo la biblioteca
@firebase/rules-unit-testing
admite la simulación deauth
en las reglas de seguridad, lo que facilita las pruebas de unidades. Además, la biblioteca admite algunas funciones específicas del emulador, como borrar todos los datos, según se detalla a continuación. - Los emuladores también aceptarán tokens de producción de Firebase Auth proporcionados a través de SDK cliente y evaluarán las reglas en consecuencia, lo que te permite conectar tu aplicación directamente a los emuladores en pruebas de integración y manuales.
Ejecuta pruebas de unidades locales
Ejecuta pruebas de unidades locales con el SDK de JavaScript de la versión 9
Firebase distribuye una biblioteca de pruebas de unidades de reglas de seguridad con el SDK de JavaScript de la versión 9 y el SDK de la versión 8. Las APIs de la biblioteca son muy diferentes. Recomendamos la biblioteca de prueba de la versión 9, que es más optimizada y requiere menos configuración para conectarse a los emuladores y, por lo tanto, evitar de forma segura el uso accidental de recursos de producción. Para la retrocompatibilidad, seguimos ofreciendo la biblioteca de pruebas de la versión 8.
- Métodos de prueba y funciones de utilidad comunes en el SDK de la versión 9
- Métodos de prueba específicos del emulador en el SDK de la versión 9
Usa el módulo @firebase/rules-unit-testing
para interactuar con el emulador
que se ejecuta de manera local. Si recibes errores ECONNREFUSED
o de tiempo de espera, vuelve a verificar que se esté ejecutando el emulador.
Recomendamos usar una versión reciente de Node.js, de modo que puedas utilizar la notación async/await
. Casi todo comportamiento que quieras probar involucra
funciones asíncronas. El módulo de pruebas está diseñado para funcionar con
código basado en promesas.
La biblioteca de pruebas de unidades de reglas de la versión 9 siempre tiene en cuenta los emuladores y nunca toca tus recursos de producción.
Importarás la biblioteca usando las instrucciones de importación de la versión 9 modular. Por ejemplo:
import {
assertFails,
assertSucceeds,
initializeTestEnvironment,
RulesTestEnvironment,
} 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.
Cuando esté importada, la implementación de pruebas de unidades implica lo siguiente:
- Crear y configurar un
RulesTestEnvironment
con una llamada ainitializeTestEnvironment
- Configurar datos de prueba sin activar reglas mediante un método
útil que te permita omitirlos temporalmente,
RulesTestEnvironment.withSecurityRulesDisabled
- Configurar paquetes de pruebas y hooks por prueba antes o después con llamadas para
limpiar los datos y el entorno de prueba, como
RulesTestEnvironment.cleanup()
oRulesTestEnvironment.clearFirestore()
- Implementar casos de prueba que imiten estados de autenticación mediante
RulesTestEnvironment.authenticatedContext
yRulesTestEnvironment.unauthenticatedContext
Métodos y funciones de utilidad comunes
Consulta también los métodos de prueba específicos del emulador en el SDK de la versión 9.
initializeTestEnvironment() => RulesTestEnvironment
Esta función inicializa un entorno de pruebas para la prueba de unidades de reglas. Llama a esta función primero para la configuración de prueba. Si la ejecución es correcta, se deben ejecutar emuladores.
La función acepta un objeto opcional que define una TestEnvironmentConfig
,
que puede consistir en un ID del proyecto y en parámetros de configuración del emulador.
let testEnv = await initializeTestEnvironment({ projectId: "demo-project-1234", firestore: { rules: fs.readFileSync("firestore.rules", "utf8"), }, });
RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext
Este método crea un RulesTestContext
, que se comporta como un usuario
autenticado de Authentication. Las solicitudes creadas a través del contexto mostrado tendrán un token de
autenticación ficticio adjunto. De manera opcional, pasa un objeto que defina reclamaciones personalizadas o
anule las cargas útiles del token de Authentication.
Usa en tus pruebas el objeto de contexto de prueba que se muestra para acceder a cualquier instancia
del emulador configurada, incluidas las configuradas 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
Este método crea un RulesTestContext
, que se comporta como un cliente que
no accedió mediante Authentication. Las solicitudes creadas a través del contexto mostrado no
tendrán tokens de Firebase Auth adjuntos.
Usa en tus pruebas el objeto de contexto de prueba que se muestra para acceder a cualquier instancia
del emulador configurada, incluidas las configuradas 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()
Ejecuta una función de configuración de prueba con un contexto que se comporte como si estuvieran inhabilitadas las reglas de seguridad.
Este método usa una función de devolución de llamada, que toma el contexto que omite las reglas de seguridad y muestra una promesa. El contexto se destruirá cuando la promesa se resuelva o rechace.
RulesTestEnvironment.cleanup()
Este método destruye todos los RulesTestContexts
creados en el entorno de prueba y
limpia los recursos subyacentes, lo que permite una salida limpia.
Este método no cambia el estado de los emuladores de ninguna manera. Para restablecer datos entre pruebas, usa el método de eliminación de datos específico del emulador de la aplicación.
assertSucceeds(pr: Promise<any>)) => Promise<any>
Esta es una función de utilidad de caso de prueba.
La función afirma que la promesa proporcionada de una operación del emulador se resolverá sin infringir las reglas de seguridad.
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });
assertFails(pr: Promise<any>)) => Promise<any>
Esta es una función de utilidad de caso de prueba.
La función afirma que la promesa proporcionada de una operación del emulador se rechazará con una infracción de las reglas de seguridad.
await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });
Métodos específicos del emulador
Consulta también los métodos de prueba y las funciones de utilidad comunes en el SDK de la versión 9.
RulesTestEnvironment.clearFirestore() => Promise<void>
Este método borra los datos de la base de datos de Firestore que pertenecen al
projectId
configurado para el emulador de Firestore.
RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;
Con este método, se obtiene una instancia de Firestore para este contexto de prueba. La instancia del SDK cliente de Firebase JS que se muestra se puede usar con las API del SDK cliente (compatibles con la versión 9 modular o la versión 9).
Visualiza las evaluaciones de las reglas
El emulador de Cloud Firestore te permite visualizar solicitudes de clientes en la IU de Emulator Suite, incluido el seguimiento de la evaluación de reglas de seguridad de Firebase.
Abre la pestaña Firestore > Solicitudes para ver la secuencia de evaluación detallada de cada solicitud.
Genera informes de prueba
Luego de ejecutar un conjunto de pruebas, puedes acceder a los informes de cobertura de pruebas que muestran cómo se evaluaron las reglas de seguridad.
Para obtenerlos, consulta un extremo expuesto en el emulador mientras se ejecuta. Usa la siguiente URL para obtener una versión compatible con navegadores:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html
Esto divide tus reglas en expresiones y subexpresiones sobre las que puedes desplazar el mouse para obtener más información, como la cantidad de evaluaciones y los valores mostrados. Si quieres acceder a la versión JSON sin procesar de los datos, incluye la siguiente URL en la consulta:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage
Diferencias entre el emulador y la producción
- No tienes que crear un proyecto de Cloud Firestore de manera explícita. El emulador crea automáticamente cualquier instancia a la que se acceda.
- El emulador de Cloud Firestore no funciona con el flujo normal de Firebase Authentication.
En su lugar, en el SDK de prueba de Firebase, proporcionamos el método
initializeTestApp()
en la bibliotecarules-unit-testing
, que incluye un campoauth
. El controlador de Firebase creado con este método se comportará como si se hubiera autenticado correctamente como cualquier entidad proporcionada. Si pasasnull
, se comportará como un usuario no autenticado (por ejemplo, fallarán las reglasauth != null
).
Soluciona problemas conocidos
Mientras usas el emulador de Cloud Firestore, podrías tener los siguientes problemas conocidos. Sigue las recomendaciones de más abajo para solucionar cualquier problema de comportamiento irregular que experimentes. Estas notas se escribieron para la biblioteca de pruebas de unidades de las reglas de seguridad, pero los enfoques generales se aplican a cualquier SDK de Firebase.
El comportamiento de prueba es incoherente
Si tus pruebas pasan y fallan ocasionalmente, incluso sin ningún cambio en ellas, es posible que debas verificar si están secuenciadas de manera correcta.
La mayoría de las interacciones con el emulador son asíncronas, por lo tanto, vuelve a verificar que todo el código asíncrono esté secuenciado de forma correcta. Puedes solucionar problemas de secuencia mediante cadenas de promesas o con el uso libre de la notación await
.
En particular, revisa las siguientes operaciones asíncronas:
- Establecer reglas de seguridad (por ejemplo, con
initializeTestEnvironment
) - Leer y escribir datos (por ejemplo, con
db.collection("users").doc("alice").get()
) - Usar aserciones operacionales, como
assertSucceeds
yassertFails
Las pruebas solo pasan la primera vez que cargas el emulador
El emulador es con estado. Almacena en la memoria todos los datos que se escriban en él, por lo que se pierden todos los datos cuando se apaga. Si estás ejecutando varias pruebas con el mismo ID de proyecto, cada prueba puede producir datos que podrían influir en las pruebas posteriores. Para evitar este comportamiento, puedes usar cualquiera de los siguientes métodos:
- Usa ID de proyecto únicos para cada prueba. Ten en cuenta que, si decides hacerlo,
deberás llamar a
initializeTestEnvironment
como parte de cada prueba. Las reglas se cargarán automáticamente solo para el ID del proyecto predeterminado. - Reestructura tus pruebas, de modo que no interactúen con datos escritos previamente (por ejemplo, usa una colección diferente para cada prueba).
- Borra todos los datos escritos durante una prueba.
La configuración de la prueba es muy complicada
Cuando configures la prueba, te recomendamos modificar los datos de tal manera que las
reglas de seguridad de Cloud Firestore no los permitan. Si las reglas hacen que la configuración de la prueba sea
compleja, intenta usar RulesTestEnvironment.withSecurityRulesDisabled
en los pasos de
configuración; de esa forma, las operaciones de lectura y escritura no activarán errores PERMISSION_DENIED
.
Luego de eso, la prueba puede realizar operaciones como usuarios autenticados o
no autenticados mediante RulesTestEnvironment.authenticatedContext
y unauthenticatedContext
,
respectivamente. Esto te permite validar que tus reglas de seguridad de Cloud Firestore permitan o rechacen
diferentes casos de manera correcta.