Ao criar seu aplicativo, talvez você queira bloquear o acesso ao banco de dados do Cloud Firestore. No entanto, antes do lançamento, você precisará de regras de segurança do Cloud Firestore com mais nuances. Com o emulador do Cloud Firestore, além de criar protótipos e testar os recursos e o comportamento geral do seu aplicativo, você pode escrever testes de unidade que verificam o comportamento das regras de segurança do Cloud Firestore.
Começo rápido
Para alguns casos de teste básicos com regras simples, experimente o exemplo de início rápido .
Entenda as regras de segurança do Cloud Firestore
Implemente regras de segurança do Firebase Authentication e Cloud Firestore para autenticação sem servidor, autorização e validação de dados ao usar as bibliotecas de cliente móvel e web.
As regras de segurança do Cloud Firestore incluem duas partes:
- Uma instrução
match
que identifica documentos no seu banco de dados. - Uma expressão
allow
que controla o acesso a esses documentos.
O Firebase Authentication verifica as credenciais dos usuários e fornece a base para sistemas de acesso baseados em usuários e em funções.
Cada solicitação de banco de dados de uma biblioteca cliente móvel/web do Cloud Firestore é avaliada em relação às suas regras de segurança antes de ler ou gravar quaisquer dados. Se as regras negarem acesso a qualquer um dos caminhos de documento especificados, toda a solicitação falhará.
Saiba mais sobre as regras de segurança do Cloud Firestore em Primeiros passos com as regras de segurança do Cloud Firestore .
Instale o emulador
Para instalar o emulador do Cloud Firestore, use a CLI do Firebase e execute o comando abaixo:
firebase setup:emulators:firestore
Execute o emulador
Comece inicializando um projeto do Firebase em seu diretório de trabalho. Esta é uma primeira etapa comum ao usar a CLI do Firebase .
firebase init
Inicie o emulador usando o seguinte comando. O emulador será executado até você encerrar o processo:
firebase emulators:start --only firestore
Em muitos casos, você deseja iniciar o emulador, executar um conjunto de testes e, em seguida, encerrar o emulador após a execução dos testes. Você pode fazer isso facilmente usando o comando emulators:exec
:
firebase emulators:exec --only firestore "./my-test-script.sh"
Quando iniciado, o emulador tentará rodar em uma porta padrão (8080). Você pode alterar a porta do emulador modificando a seção "emulators"
do arquivo firebase.json
:
{ // ... "emulators": { "firestore": { "port": "YOUR_PORT" } } }
Antes de executar o emulador
Antes de começar a usar o emulador, lembre-se do seguinte:
- O emulador carregará inicialmente as regras especificadas no campo
firestore.rules
do seu arquivofirebase.json
. Ele espera o nome de um arquivo local contendo suas regras de segurança do Cloud Firestore e aplica essas regras a todos os projetos. Se você não fornecer o caminho do arquivo local ou usar o métodoloadFirestoreRules
conforme descrito abaixo, o emulador tratará todos os projetos como tendo regras abertas. - Embora a maioria dos SDKs do Firebase funcionem diretamente com os emuladores, apenas a biblioteca
@firebase/rules-unit-testing
oferece suporte à simulação deauth
nas regras de segurança, tornando os testes de unidade muito mais fáceis. Além disso, a biblioteca oferece suporte a alguns recursos específicos do emulador, como limpar todos os dados, conforme listado abaixo. - Os emuladores também aceitarão tokens de produção do Firebase Auth fornecidos por meio de SDKs de cliente e avaliarão as regras de acordo, o que permite conectar seu aplicativo diretamente aos emuladores em integração e testes manuais.
Execute testes de unidade local
Execute testes de unidade local com o SDK JavaScript v9
O Firebase distribui uma biblioteca de teste de unidade de regras de segurança com seu SDK JavaScript versão 9 e seu SDK versão 8. As APIs da biblioteca são significativamente diferentes. Recomendamos a biblioteca de testes v9, que é mais simplificada e requer menos configuração para conectar-se a emuladores e, assim, evitar com segurança o uso acidental de recursos de produção. Para compatibilidade com versões anteriores, continuamos disponibilizando a biblioteca de testes v8 .
- Métodos de teste comuns e funções utilitárias no SDK v9
- Métodos de teste específicos do emulador no SDK v9
Use o módulo @firebase/rules-unit-testing
para interagir com o emulador executado localmente. Se você obtiver tempos limite ou erros ECONNREFUSED
, verifique novamente se o emulador está realmente em execução.
Recomendamos fortemente o uso de uma versão recente do Node.js para que você possa usar a notação async/await
. Quase todo o comportamento que você deseja testar envolve funções assíncronas, e o módulo de teste foi projetado para funcionar com código baseado em Promise.
A biblioteca de testes unitários de regras v9 está sempre ciente dos emuladores e nunca afeta seus recursos de produção.
Você importa a biblioteca usando instruções de importação modular v9. Por exemplo:
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.
Depois de importado, a implementação de testes unitários envolve:
- Criando e configurando um
RulesTestEnvironment
com uma chamada parainitializeTestEnvironment
. - Configurar dados de teste sem acionar regras, usando um método conveniente que permite ignorá-los temporariamente,
RulesTestEnvironment.withSecurityRulesDisabled
. - Configurando o conjunto de testes e ganchos antes/depois por teste com chamadas para limpar dados e ambiente de teste, como
RulesTestEnvironment.cleanup()
ouRulesTestEnvironment.clearFirestore()
. - Implementar casos de teste que imitam estados de autenticação usando
RulesTestEnvironment.authenticatedContext
eRulesTestEnvironment.unauthenticatedContext
.
Métodos comuns e funções utilitárias
Consulte também métodos de teste específicos do emulador no SDK v9 .
initializeTestEnvironment() => RulesTestEnvironment
Esta função inicializa um ambiente de teste para testes unitários de regras. Chame esta função primeiro para configuração de teste. A execução bem-sucedida requer que os emuladores estejam em execução.
A função aceita um objeto opcional que define um TestEnvironmentConfig
, que pode consistir em um ID de projeto e definições de configuração do 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 cria um RulesTestContext
, que se comporta como um usuário de autenticação autenticado. As solicitações criadas por meio do contexto retornado terão um token de autenticação simulado anexado. Opcionalmente, passe um objeto que defina declarações ou substituições personalizadas para cargas úteis de token de autenticação.
Use o objeto de contexto de teste retornado em seus testes para acessar quaisquer instâncias de emulador configuradas, incluindo aquelas configuradas com 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 cria um RulesTestContext
, que se comporta como um cliente que não está logado via autenticação. As solicitações criadas por meio do contexto retornado não terão tokens do Firebase Auth anexados.
Use o objeto de contexto de teste retornado em seus testes para acessar quaisquer instâncias de emulador configuradas, incluindo aquelas configuradas com 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()
Execute uma função de configuração de teste com um contexto que se comporta como se as regras de segurança estivessem desabilitadas.
Este método usa uma função de retorno de chamada, que pega o contexto de desvio de regras de segurança e retorna uma promessa. O contexto será destruído assim que a promessa for resolvida/rejeitada.
RulesTestEnvironment.cleanup()
Este método destrói todos os RulesTestContexts
criados no ambiente de teste e limpa os recursos subjacentes, permitindo uma saída limpa.
Este método não altera o estado dos emuladores de forma alguma. Para redefinir dados entre testes, use o método de limpeza de dados específico do emulador do aplicativo.
assertSucceeds(pr: Promise<any>)) => Promise<any>
Esta é uma função utilitária de caso de teste.
A função afirma que a operação Promise fornecida envolvendo um emulador será resolvida sem violações das regras de segurança.
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });
assertFails(pr: Promise<any>)) => Promise<any>
Esta é uma função utilitária de caso de teste.
A função afirma que a promessa fornecida envolvendo uma operação de emulador será rejeitada com uma violação das regras de segurança.
await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });
Métodos específicos do emulador
Consulte também métodos de teste comuns e funções utilitárias no SDK v9 .
RulesTestEnvironment.clearFirestore() => Promise<void>
Este método limpa os dados no banco de dados do Firestore que pertencem ao projectId
configurado para o emulador do Firestore.
RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;
Este método obtém uma instância do Firestore para este contexto de teste. A instância do Firebase JS Client SDK retornada pode ser usada com as APIs do SDK do cliente (v9 modular ou v9 compatível).
Visualize avaliações de regras
O emulador do Cloud Firestore permite visualizar solicitações de clientes na IU do Emulator Suite, incluindo rastreamento de avaliação para regras de segurança do Firebase.
Abra a guia Firestore > Solicitações para visualizar a sequência de avaliação detalhada de cada solicitação.
Gerar relatórios de teste
Depois de executar um conjunto de testes, você poderá acessar relatórios de cobertura de testes que mostram como cada uma de suas regras de segurança foi avaliada.
Para obter os relatórios, consulte um ponto de extremidade exposto no emulador enquanto ele estiver em execução. Para uma versão amigável ao navegador, use o seguinte URL:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html
Isso divide suas regras em expressões e subexpressões que você pode passar o mouse para obter mais informações, incluindo o número de avaliações e valores retornados. Para a versão JSON bruta desses dados, inclua o seguinte URL na sua consulta:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage
Diferenças entre o emulador e a produção
- Você não precisa criar explicitamente um projeto do Cloud Firestore. O emulador cria automaticamente qualquer instância acessada.
- O emulador do Cloud Firestore não funciona com o fluxo normal do Firebase Authentication. Em vez disso, no Firebase Test SDK, fornecemos o método
initializeTestApp()
na bibliotecarules-unit-testing
, que usa um campoauth
. O identificador do Firebase criado usando esse método se comportará como se tivesse sido autenticado com sucesso como qualquer entidade que você fornecer. Se você passarnull
, ele se comportará como um usuário não autenticado (auth != null
regras falharão, por exemplo).
Solucionar problemas conhecidos
Ao usar o emulador do Cloud Firestore, você poderá encontrar os seguintes problemas conhecidos. Siga as orientações abaixo para solucionar qualquer comportamento irregular que você esteja enfrentando. Estas notas foram escritas tendo em mente a biblioteca de testes unitários de regras de segurança, mas as abordagens gerais são aplicáveis a qualquer SDK do Firebase.
O comportamento do teste é inconsistente
Se seus testes forem aprovados e reprovados ocasionalmente, mesmo sem nenhuma alteração nos testes em si, talvez seja necessário verificar se eles estão sequenciados corretamente. A maioria das interações com o emulador são assíncronas, portanto, verifique novamente se todo o código assíncrono está sequenciado corretamente. Você pode corrigir o sequenciamento encadeando promessas ou usando a notação await
liberalmente.
Em particular, revise as seguintes operações assíncronas:
- Definir regras de segurança, por exemplo,
initializeTestEnvironment
. - Lendo e gravando dados, com, por exemplo,
db.collection("users").doc("alice").get()
. - Asserções operacionais, incluindo
assertSucceeds
eassertFails
.
Os testes só passam na primeira vez que você carrega o emulador
O emulador tem estado. Ele armazena todos os dados gravados na memória, portanto, todos os dados são perdidos sempre que o emulador é desligado. Se você estiver executando vários testes no mesmo ID de projeto, cada teste poderá produzir dados que podem influenciar os testes subsequentes. Você pode usar qualquer um dos seguintes métodos para ignorar esse comportamento:
- Use IDs de projeto exclusivos para cada teste. Observe que se você optar por fazer isso, precisará chamar
initializeTestEnvironment
como parte de cada teste; as regras são carregadas automaticamente apenas para o ID do projeto padrão. - Reestruture seus testes para que eles não interajam com dados gravados anteriormente (por exemplo, use uma coleção diferente para cada teste).
- Exclua todos os dados gravados durante um teste.
A configuração do teste é muito complicada
Ao configurar seu teste, você pode modificar os dados de uma forma que as regras de segurança do Cloud Firestore não permitem. Se suas regras estão tornando a configuração do teste complexa, tente usar RulesTestEnvironment.withSecurityRulesDisabled
nas etapas de configuração, para que leituras e gravações não acionem erros PERMISSION_DENIED
.
Depois disso, seu teste pode executar operações como um usuário autenticado ou não autenticado usando RulesTestEnvironment.authenticatedContext
e unauthenticatedContext
respectivamente. Isso permite que você valide se suas regras de segurança do Cloud Firestore permitem/negam diferentes casos corretamente.