Compila pruebas de unidades

Con Firebase Local Emulator Suite es más sencillo validar por completo las funciones y el comportamiento de tu app. Además, es una herramienta excelente para verificar tu configuración de reglas de seguridad de Firebase. Usa los emuladores de Firebase para ejecutar y automatizar pruebas de unidades en un entorno local. Los métodos descritos en este documento te pueden ayudar con la compilación y automatización de pruebas de unidades para tu app que validen las reglas aplicadas.

Si aún no lo has hecho, configura los emuladores de Firebase.

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 los campos firestore.rules o “storage.rules” de tu archivo firebase.json. Si el archivo no existe y no usas los métodos loadFirestoreRules o “loadStorageRules” como se describe a continuación, el emulador trata todos los proyectos como si tuvieran reglas abiertas.
  • Si bien la mayoría de los SDKs de Firebase funcionan con los emuladores de forma directa, solo la biblioteca @firebase/rules-unit-testing admite la simulación de auth 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.

Diferencias entre los emuladores de bases de datos y la producción

  • No es necesario crear una instancia de base de datos de manera explícita. El emulador creará automáticamente cualquier instancia de base de datos a la que se acceda.
  • Cada base de datos nueva se inicia con reglas cerradas, por lo que los usuarios que no sean administradores no podrán realizar operaciones de lectura ni escritura.
  • Se aplican los límites y cuotas del plan Spark a todas las bases de datos emuladas (en particular, esto limita cada instancia a 100 conexiones simultáneas).
  • Cualquier base de datos aceptará la string "owner" como token de autenticación del administrador.
  • Actualmente los emuladores no tienen interacciones operativas con otros productos de Firebase. En particular, no funciona el flujo normal de Firebase Authentication. En su lugar, puedes usar el método initializeTestApp() en la biblioteca rules-unit-testing, que emplea un campo auth. El objeto de Firebase que se cree con este método se comportará como si se autenticara correctamente al igual que cualquier entidad proporcionada. Si pasas null, se comportará como un usuario no autenticado (por ejemplo, fallarán las reglas auth != null).

Interactúa con el emulador de Realtime Database

Se puede acceder a una instancia de producción de Firebase Realtime Database en un subdominio de firebaseio.com, y puedes acceder a la API de REST de la siguiente manera:

https://<database_name>.firebaseio.com/path/to/my/data.json

El emulador se ejecuta de manera local y está disponible en localhost:9000. Para interactuar con una instancia de base de datos específica, deberás usar el parámetro de búsqueda ns a fin de especificar el nombre de la base de datos.

http://localhost:9000/path/to/my/data.json?ns=<database_name>

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.

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 a initializeTestEnvironment
  • 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() o RulesTestEnvironment.clearFirestore()
  • Implementar casos de prueba que imiten estados de autenticación mediante RulesTestEnvironment.authenticatedContext y RulesTestEnvironment.unauthenticatedContext

Métodos y funciones de utilidad comunes

Consulta también los métodos de prueba específicos del emulador con la API modular.

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 con la API modular.

Cloud Firestore

Cloud Firestore

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).

Realtime Database

Realtime Database

RulesTestEnvironment.clearDatabase() => Promise<void>

Este método borra los datos de Realtime Database que pertenecen al projectId configurado para el emulador de Realtime Database.

RulesTestContext.database(databaseURL?: Firestore.FirestoreSettings) => Firestore;

Obtén una instancia de Realtime Database para este contexto de prueba. La instancia del SDK cliente de Firebase JS que se muestra se puede usar con las APIs del SDK cliente (modulares o con espacio de nombres, versión 9 o posterior). El método acepta una URL de la instancia de Realtime Database. Si se especifica, muestra una instancia para una versión emulada del espacio de nombres con los parámetros extraídos de la URL.

Cloud Storage

Cloud Storage

RulesTestEnvironment.clearStorage() => Promise<void>

Este método borra objetos y metadatos en buckets de almacenamiento que pertenecen al projectId configurado para el emulador de Cloud Storage.

RulesTestContext.storage(bucketUrl?: string) => Firebase Storage;

Además, muestra una instancia de Storage configurada para conectarse al emulador y acepta una URL gs:// para enviar el bucket de Firebase Storage a fin de realizar pruebas. Si se especifica, muestra una instancia de Storage para una versión emulada del nombre del bucket.

Ejecuta pruebas de unidades locales con el SDK de JavaScript de la versión 8

Selecciona un producto y conoce los métodos que usa el SDK de Firebase Test para interactuar con el emulador.

Cloud Firestore

initializeTestApp({ projectId: string, auth: Object }) => FirebaseApp

Este método muestra una app de Firebase inicializada correspondiente al ID del proyecto y la variable de auth especificada en las opciones. Úsalo para crear una app autenticada como un usuario específico que puedes emplear durante las pruebas.

firebase.initializeTestApp({
  projectId: "my-test-project",
  auth: { uid: "alice", email: "alice@example.com" }
});

initializeAdminApp({ projectId: string }) => FirebaseApp

Este método muestra una app de administración de Firebase inicializada, que omite las reglas de seguridad cuando realiza operaciones de lectura y escritura. Usa el método a fin de crear una app autenticada como un administrador para configurar el estado de las pruebas.

firebase.initializeAdminApp({ projectId: "my-test-project" });
    

apps() => [FirebaseApp] Este método muestra todas las apps de administración y pruebas inicializadas actualmente. Úsalo para limpiar las apps entre pruebas o después de ellas.

Promise.all(firebase.apps().map(app => app.delete()))

loadFirestoreRules({ projectId: string, rules: Object }) => Promise

Este método envía reglas a una base de datos que se ejecuta localmente. Requiere un objeto que especifique las reglas como string. Usa este método para configurar las reglas de tu base de datos.

firebase.loadFirestoreRules({
  projectId: "my-test-project",
  rules: fs.readFileSync("/path/to/firestore.rules", "utf8")
});
    

assertFails(pr: Promise) => Promise

Este método muestra una promesa que se rechaza si la entrada es correcta o se cumple correctamente si la entrada se rechaza. Úsalo para confirmar si fallan las operaciones de lectura o escritura de una base de datos.

firebase.assertFails(app.firestore().collection("private").doc("super-secret-document").get());
    

assertSucceeds(pr: Promise) => Promise

Este método muestra una promesa que se cumple correctamente si la entrada es correcta o se rechaza si la entrada se rechaza. Úsalo para confirmar si se completan correctamente las operaciones de lectura o escritura de una base de datos.

firebase.assertSucceeds(app.firestore().collection("public").doc("test-document").get());
    

clearFirestoreData({ projectId: string }) => Promise

Este método borra todos los datos asociados a un proyecto determinado de la instancia de Firestore que se ejecuta de manera local. Usa este método para realizar la limpieza después de las pruebas.

firebase.clearFirestoreData({
  projectId: "my-test-project"
});
   

Realtime Database

Realtime Database

initializeTestApp({ databaseName: string, auth: Object }) => FirebaseApp

Úsalo para crear una app autenticada como un usuario específico que puedes usar durante las pruebas.

Muestra una app de Firebase inicializada correspondiente al nombre de la base de datos y la anulación de la variable auth que se especificó en las opciones.

firebase.initializeTestApp({
  databaseName: "my-database",
  auth: { uid: "alice" }
});

initializeAdminApp({ databaseName: string }) => FirebaseApp

Úsalo a fin de crear una app autenticada como un administrador para configurar el estado de las pruebas.

Muestra una app de administración de Firebase inicializada correspondiente al nombre de la base de datos que se especificó en las opciones. Esta app ignora las reglas de seguridad al momento de leer o escribir en la base de datos.

firebase.initializeAdminApp({ databaseName: "my-database" });

loadDatabaseRules({ databaseName: string, rules: Object }) => Promise

Úsalo para configurar las reglas de tu base de datos.

Envía reglas a una base de datos que se ejecuta localmente. Toma un objeto de opciones que indica tu “databaseName” y tus “rules” como strings.

firebase
      .loadDatabaseRules({
        databaseName: "my-database",
        rules: "{'rules': {'.read': false, '.write': false}}"
      });

apps() => [FirebaseApp]

Muestra todas las apps de administración y prueba inicializadas.

Úsalo para limpiar las apps entre pruebas o a su término (ten en cuenta que las apps inicializadas con objetos de escucha activos evitan la salida de JavaScript):

 Promise.all(firebase.apps().map(app => app.delete()))

assertFails(pr: Promise) => Promise

Muestra una promesa que se rechaza si la entrada es correcta y se cumple correctamente si se rechaza la entrada.

Úsalo para confirmar que fallan las operaciones de lectura o escritura de una base de datos:

firebase.assertFails(app.database().ref("secret").once("value"));

assertSucceeds(pr: Promise) => Promise

Muestra una promesa que se cumple correctamente si la entrada es correcta y se rechaza si la entrada se rechaza.

Úsalo para declarar que una base de datos puede leer o escribir:

firebase.assertSucceeds(app.database().ref("public").once("value"));

Cloud Storage

Cloud Storage

initializeTestApp({ storageBucket: string, auth: Object }) => FirebaseApp

Úsalo para crear una app autenticada como un usuario específico que puedes usar durante las pruebas.

Muestra una app de Firebase inicializada correspondiente al nombre del bucket de almacenamiento y la anulación de la variable auth que se especificó en las opciones.

firebase.initializeTestApp({
  storageBucket: "my-bucket",
  auth: { uid: "alice" }
});

initializeAdminApp({ storageBucket: string }) => FirebaseApp

Úsalo a fin de crear una app autenticada como un administrador para configurar el estado de las pruebas.

Muestra una app de administración de Firebase inicializada correspondiente al nombre del bucket de almacenamiento especificado en las opciones. Esta app omite las reglas de seguridad al momento de leer y escribir en el bucket.

firebase.initializeAdminApp({ storageBucket: "my-bucket" });

loadStorageRules({ storageBucket: string, rules: Object }) => Promise

Úsalo para configurar las reglas de tu bucket de almacenamiento.

Envía reglas a buckets de almacenamiento administrados de manera local. Toma un objeto de opciones que indica tu “storageBucket” y tus “reglas” como strings.

firebase
      .loadStorageRules({
        storageBucket: "my-bucket",
        rules: fs.readFileSync("/path/to/storage.rules", "utf8")
      });

apps() => [FirebaseApp]

Muestra todas las apps de administración y prueba inicializadas.

Úsalo para limpiar las apps entre pruebas o a su término (ten en cuenta que las apps inicializadas con objetos de escucha activos evitan la salida de JavaScript):

 Promise.all(firebase.apps().map(app => app.delete()))

assertFails(pr: Promise) => Promise

Muestra una promesa que se rechaza si la entrada es correcta y se cumple correctamente si se rechaza la entrada.

Úsalo para confirmar que falla la lectura o escritura de un bucket de almacenamiento:

firebase.assertFails(app.storage().ref("letters/private.doc").getMetadata());

assertSucceeds(pr: Promise) => Promise

Muestra una promesa que se cumple correctamente si la entrada es correcta y que se rechaza si la entrada se rechaza.

Úsalo para confirmar que se logró la lectura o escritura de un bucket de almacenamiento:

firebase.assertFails(app.storage().ref("images/cat.png").getMetadata());

API de la biblioteca de pruebas de unidades de reglas para el SDK de JS de la versión 8

Selecciona un producto y conoce los métodos que usa el SDK de Firebase Test para interactuar con el emulador.

Cloud Firestore

Cloud Firestore

initializeTestApp({ projectId: string, auth: Object }) => FirebaseApp

Este método muestra una app de Firebase inicializada correspondiente al ID del proyecto y la variable de auth especificada en las opciones. Úsalo para crear una app autenticada como un usuario específico que puedes emplear durante las pruebas.

firebase.initializeTestApp({
  projectId: "my-test-project",
  auth: { uid: "alice", email: "alice@example.com" }
});

initializeAdminApp({ projectId: string }) => FirebaseApp

Este método muestra una app de administración de Firebase inicializada, que omite las reglas de seguridad cuando realiza operaciones de lectura y escritura. Usa el método a fin de crear una app autenticada como un administrador para configurar el estado de las pruebas.

firebase.initializeAdminApp({ projectId: "my-test-project" });
    

apps() => [FirebaseApp] Este método muestra todas las apps de administración y pruebas inicializadas actualmente. Úsalo para limpiar las apps entre pruebas o después de ellas.

Promise.all(firebase.apps().map(app => app.delete()))

loadFirestoreRules({ projectId: string, rules: Object }) => Promise

Este método envía reglas a una base de datos que se ejecuta localmente. Requiere un objeto que especifique las reglas como string. Usa este método para configurar las reglas de tu base de datos.

firebase.loadFirestoreRules({
  projectId: "my-test-project",
  rules: fs.readFileSync("/path/to/firestore.rules", "utf8")
});
    

assertFails(pr: Promise) => Promise

Este método muestra una promesa que se rechaza si la entrada es correcta o se cumple correctamente si la entrada se rechaza. Úsalo para confirmar si fallan las operaciones de lectura o escritura de una base de datos.

firebase.assertFails(app.firestore().collection("private").doc("super-secret-document").get());
    

assertSucceeds(pr: Promise) => Promise

Este método muestra una promesa que se cumple correctamente si la entrada es correcta o se rechaza si la entrada se rechaza. Úsalo para confirmar si se completan correctamente las operaciones de lectura o escritura de una base de datos.

firebase.assertSucceeds(app.firestore().collection("public").doc("test-document").get());
    

clearFirestoreData({ projectId: string }) => Promise

Este método borra todos los datos asociados a un proyecto determinado de la instancia de Firestore que se ejecuta de manera local. Usa este método para realizar la limpieza después de las pruebas.

firebase.clearFirestoreData({
  projectId: "my-test-project"
});
   

Realtime Database

Realtime Database

initializeTestApp({ databaseName: string, auth: Object }) => FirebaseApp

Úsalo para crear una app autenticada como un usuario específico que puedes usar durante las pruebas.

Muestra una app de Firebase inicializada correspondiente al nombre de la base de datos y la anulación de la variable auth que se especificó en las opciones.

firebase.initializeTestApp({
  databaseName: "my-database",
  auth: { uid: "alice" }
});

initializeAdminApp({ databaseName: string }) => FirebaseApp

Úsalo a fin de crear una app autenticada como un administrador para configurar el estado de las pruebas.

Muestra una app de administración de Firebase inicializada correspondiente al nombre de la base de datos que se especificó en las opciones. Esta app ignora las reglas de seguridad al momento de leer o escribir en la base de datos.

firebase.initializeAdminApp({ databaseName: "my-database" });

loadDatabaseRules({ databaseName: string, rules: Object }) => Promise

Úsalo para configurar las reglas de tu base de datos.

Envía reglas a una base de datos que se ejecuta localmente. Toma un objeto de opciones que indica tu “databaseName” y tus “rules” como strings.

firebase
      .loadDatabaseRules({
        databaseName: "my-database",
        rules: "{'rules': {'.read': false, '.write': false}}"
      });

apps() => [FirebaseApp]

Muestra todas las apps de administración y prueba inicializadas.

Úsalo para limpiar las apps entre pruebas o a su término (ten en cuenta que las apps inicializadas con objetos de escucha activos evitan la salida de JavaScript):

 Promise.all(firebase.apps().map(app => app.delete()))

assertFails(pr: Promise) => Promise

Muestra una promesa que se rechaza si la entrada es correcta y se cumple correctamente si se rechaza la entrada.

Úsalo para confirmar que fallan las operaciones de lectura o escritura de una base de datos:

firebase.assertFails(app.database().ref("secret").once("value"));

assertSucceeds(pr: Promise) => Promise

Muestra una promesa que se cumple correctamente si la entrada es correcta y se rechaza si la entrada se rechaza.

Úsalo para declarar que una base de datos puede leer o escribir:

firebase.assertSucceeds(app.database().ref("public").once("value"));

Cloud Storage

Cloud Storage

initializeTestApp({ storageBucket: string, auth: Object }) => FirebaseApp

Úsalo para crear una app autenticada como un usuario específico que puedes usar durante las pruebas.

Muestra una app de Firebase inicializada correspondiente al nombre del bucket de almacenamiento y la anulación de la variable auth que se especificó en las opciones.

firebase.initializeTestApp({
  storageBucket: "my-bucket",
  auth: { uid: "alice" }
});

initializeAdminApp({ storageBucket: string }) => FirebaseApp

Úsalo a fin de crear una app autenticada como un administrador para configurar el estado de las pruebas.

Muestra una app de administración de Firebase inicializada correspondiente al nombre del bucket de almacenamiento especificado en las opciones. Esta app omite las reglas de seguridad al momento de leer y escribir en el bucket.

firebase.initializeAdminApp({ storageBucket: "my-bucket" });

loadStorageRules({ storageBucket: string, rules: Object }) => Promise

Úsalo para configurar las reglas de tu bucket de almacenamiento.

Envía reglas a buckets de almacenamiento administrados de manera local. Toma un objeto de opciones que indica tu “storageBucket” y tus “reglas” como strings.

firebase
      .loadStorageRules({
        storageBucket: "my-bucket",
        rules: fs.readFileSync("/path/to/storage.rules", "utf8")
      });

apps() => [FirebaseApp]

Muestra todas las apps de administración y prueba inicializadas.

Úsalo para limpiar las apps entre pruebas o a su término (ten en cuenta que las apps inicializadas con objetos de escucha activos evitan la salida de JavaScript):

 Promise.all(firebase.apps().map(app => app.delete()))

assertFails(pr: Promise) => Promise

Muestra una promesa que se rechaza si la entrada es correcta y se cumple correctamente si se rechaza la entrada.

Úsalo para confirmar que falla la lectura o escritura de un bucket de almacenamiento:

firebase.assertFails(app.storage().ref("letters/private.doc").getMetadata());

assertSucceeds(pr: Promise) => Promise

Muestra una promesa que se cumple correctamente si la entrada es correcta y que se rechaza si la entrada se rechaza.

Úsalo para confirmar que se logró la lectura o escritura de un bucket de almacenamiento:

firebase.assertFails(app.storage().ref("images/cat.png").getMetadata());