Teste as regras de segurança
À medida que cria a sua app, pode querer restringir o acesso à base de dados do Firestore no modo nativo. No entanto, antes de iniciar, precisa de regras de segurança do Firestore mais detalhadas. Com o emulador do Firestore no modo nativo, além de criar protótipos e testar as funcionalidades e o comportamento gerais da sua app, pode escrever testes unitários que verifiquem o comportamento das suas regras de segurança do Firestore.
Início rápido
Para alguns exemplos de testes básicos com regras simples, experimente o exemplo de início rápido.
Compreenda as regras de segurança do Firestore
Implemente a autenticação do Firebase e as regras de segurança do Firestore para autenticação, autorização e validação de dados sem servidor quando usa as bibliotecas de cliente Web e para dispositivos móveis.
As regras de segurança do Firestore incluem duas partes:
- Uma declaração
matchque identifica documentos na sua base de dados. - Uma expressão
allowque controla o acesso a esses documentos.
A Firebase Authentication valida as credenciais dos utilizadores e fornece a base para sistemas de acesso baseados em utilizadores e funções.
Cada pedido de base de dados de uma biblioteca de cliente Web/para dispositivos móveis do Firestore é avaliado em função das suas regras de segurança antes de ler ou escrever dados. Se as regras recusarem o acesso a qualquer um dos caminhos de documentos especificados, todo o pedido falha.
Saiba mais sobre as regras de segurança do Firestore em Comece a usar as regras de segurança do Firestore.
Instale o emulador
Para instalar o emulador do Firestore no modo nativo, use a Firebase CLI e execute o comando abaixo:
firebase setup:emulators:firestore
Execute o emulador
Comece por inicializar um projeto do Firebase no seu diretório de trabalho. Este é um primeiro passo comum quando usa a Firebase CLI.
firebase init
Inicie o emulador com o seguinte comando. O emulador é executado até terminar o processo:
firebase emulators:start --only firestore
Em muitos casos, quer iniciar o emulador, executar um conjunto de testes e, em seguida, desligar o emulador após a execução dos testes. Pode fazê-lo facilmente através do comando emulators:exec:
firebase emulators:exec --only firestore "./my-test-script.sh"
Quando iniciado, o emulador tenta ser executado numa porta predefinida (8080). Pode alterar a porta do emulador modificando a secção "emulators" do ficheiro firebase.json:
{
// ...
"emulators": {
"firestore": {
"port": "YOUR_PORT"
}
}
}Antes de executar o emulador
Antes de começar a usar o emulador, tenha em atenção o seguinte:
- Inicialmente, o emulador carrega as regras especificadas no campo
firestore.rulesdo ficheirofirebase.json. Espera o nome de um ficheiro local que contenha as suas regras de segurança do Firestore e aplica essas regras a todos os projetos. Se não fornecer o caminho do ficheiro local ou usar o métodoloadFirestoreRulesconforme descrito abaixo, o emulador trata todos os projetos como tendo regras abertas. - Embora a maioria dos SDKs do Firebase funcione diretamente com os emuladores, apenas a biblioteca
@firebase/rules-unit-testingsuporta aauthsimulaçãoauthnas regras de segurança, o que facilita muito os testes unitários. Além disso, a biblioteca suporta algumas funcionalidades específicas do emulador, como limpar todos os dados, conforme indicado abaixo. - Os emuladores também aceitam tokens de produção da Firebase Auth fornecidos através de SDKs do cliente e avaliam as regras em conformidade, o que permite ligar a sua aplicação diretamente aos emuladores em testes de integração e manuais.
Execute testes unitários locais
Execute testes unitários locais com o SDK JavaScript v9
O Firebase distribui uma biblioteca de testes unitários das regras de segurança com o respetivo SDK JavaScript versão 9 e SDK versão 8. As APIs de bibliotecas são significativamente diferentes. Recomendamos a biblioteca de testes v9, que é mais simplificada e requer menos configuração para se ligar a emuladores e, assim, evitar em segurança a utilização acidental de recursos de produção. Para compatibilidade com versões anteriores, continuamos a disponibilizar a biblioteca de testes v8.
- Métodos de teste comuns e funções de utilidade 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
que é executado localmente. Se receber tempos limite ou erros ECONNREFUSED, verifique novamente se o emulador está realmente em execução.
Recomendamos vivamente que use uma versão recente do Node.js para poder usar a notação async/await. Quase todo o comportamento que pode querer testar envolve funções assíncronas, e o módulo de teste foi concebido para funcionar com código baseado em promessas.
A biblioteca de testes de unidades de regras v9 tem sempre conhecimento dos emuladores e nunca afeta os seus recursos de produção.
Importa a biblioteca através de declarações de importação modulares da 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 importados, a implementação de testes de unidades envolve o seguinte:
- Criar e configurar um
RulesTestEnvironmentcom uma chamada parainitializeTestEnvironment. - Configurar dados de teste sem acionar regras, usando um método simples que lhe permite ignorá-las temporariamente,
RulesTestEnvironment.withSecurityRulesDisabled. - Configurar o conjunto de testes e os hooks antes/depois por teste com chamadas para limpar os dados de teste e o ambiente, como
RulesTestEnvironment.cleanup()ouRulesTestEnvironment.clearFirestore(). - Implementar exemplos de testes que imitam estados de autenticação usando
RulesTestEnvironment.authenticatedContexteRulesTestEnvironment.unauthenticatedContext.
Métodos comuns e funções de utilidade
Consulte também os métodos de teste específicos do emulador no SDK v9.
initializeTestEnvironment() => RulesTestEnvironment
Esta função inicializa um ambiente de teste para testes de unidades de regras. Chame esta função primeiro para a configuração do 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 num ID do projeto e nas 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 utilizador de autenticação autenticado. Os pedidos criados através do contexto devolvido têm um símbolo de autenticação simulado anexado. Opcionalmente, transmita um objeto que defina reivindicações personalizadas ou substituições para payloads de tokens de autenticação.
Use o objeto de contexto de teste devolvido nos seus testes para aceder a quaisquer instâncias do emulador configuradas, incluindo as 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().doc('/users/alice'), { ... });
RulesTestEnvironment.unauthenticatedContext() => RulesTestContext
Este método cria um RulesTestContext, que se comporta como um cliente que não tem sessão iniciada através da autenticação. Os pedidos criados através do contexto devolvido não
têm tokens de autenticação do Firebase anexados.
Use o objeto de contexto de teste devolvido nos seus testes para aceder a quaisquer instâncias do emulador configuradas, incluindo as 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 desativadas.
Este método usa uma função de chamada de retorno, que usa o contexto de ignorar as regras de segurança e devolve uma promessa. O contexto é 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 repor os dados entre testes, use o método de limpeza de dados específico do emulador de aplicações.
assertSucceeds(pr: Promise<any>)) => Promise<any>
Esta é uma função de utilidade de teste.
A função afirma que a promessa fornecida que envolve uma operação do 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 de utilidade de teste.
A função afirma que a promessa fornecida que envolve uma operação do 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 os métodos de teste comuns e as funções de utilidade no SDK v9.
RulesTestEnvironment.clearFirestore() => Promise<void>
Este método limpa os dados na base 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 SDK de cliente JS do Firebase devolvida pode ser usada com as APIs do SDK de cliente (modular v9 ou compat v9).
Visualize as avaliações de regras
O emulador do Firestore no modo nativo permite-lhe visualizar pedidos de clientes na IU do Emulator Suite, incluindo a monitorização da avaliação para as regras de segurança do Firebase.
Abra o separador Firestore > Pedidos para ver a sequência de avaliação detalhada de cada pedido.
Gere relatórios de testes
Depois de executar um conjunto de testes, pode aceder a relatórios de cobertura de testes que mostram como cada uma das suas regras de segurança foi avaliada.
Para receber os relatórios, consulte um ponto final exposto no emulador enquanto está em execução. Para uma versão compatível com o navegador, use o seguinte URL:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html
Isto divide as suas regras em expressões e subexpressões sobre as quais pode passar o cursor do rato para ver mais informações, incluindo o número de avaliações e os valores devolvidos. Para a versão JSON não processada destes 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
- Não tem de criar explicitamente um projeto do Firestore no modo nativo. O emulador cria automaticamente qualquer instância acedida.
- O emulador do Firestore no modo nativo não funciona com o fluxo normal do Firebase Authentication.
Em alternativa, no SDK de teste do Firebase, fornecemos o método
initializeTestApp()na bibliotecarules-unit-testing, que usa um campoauth. O identificador do Firebase criado através deste método vai comportar-se como se tivesse sido autenticado com êxito como qualquer entidade que fornecer. Se transmitirnull, o comportamento é o de um utilizador não autenticado (por exemplo, as regrasauth != nullfalham).
Resolva problemas conhecidos
À medida que usa o emulador do Firestore no modo nativo, pode deparar-se com os seguintes problemas conhecidos. Siga as orientações abaixo para resolver qualquer comportamento irregular que esteja a experienciar. Estas notas foram escritas tendo em conta a biblioteca de testes unitários das regras de segurança, mas as abordagens gerais são aplicáveis a qualquer SDK do Firebase.
O comportamento do teste é inconsistente
Se os seus testes passarem e falharem ocasionalmente, mesmo sem alterações aos próprios testes, pode ter de verificar se estão sequenciados corretamente.
A maioria das interações com o emulador é assíncrona, por isso, verifique novamente se todo o código assíncrono está sequenciado corretamente. Pode corrigir a sequenciação encadeando promessas ou usando a notação await de forma liberal.
Em particular, reveja as seguintes operações assíncronas:
- Definir regras de segurança, por exemplo, com
initializeTestEnvironment. - Ler e escrever dados, por exemplo, com
db.collection("users").doc("alice").get(). - Afirmações operacionais, incluindo
assertSucceedseassertFails.
Os testes só são aprovados na primeira vez que carrega o emulador
O emulador tem estado. Armazena todos os dados escritos na memória, pelo que todos os dados são perdidos sempre que o emulador é encerrado. Se estiver a executar vários testes com o mesmo ID do projeto, cada teste pode produzir dados que podem influenciar os testes subsequentes. Pode usar qualquer um dos seguintes métodos para evitar este comportamento:
- Use IDs de projetos únicos para cada teste. Tenha em atenção que, se optar por fazê-lo, tem de chamar
initializeTestEnvironmentcomo parte de cada teste. As regras só são carregadas automaticamente para o ID do projeto predefinido. - Reestruture os testes para que não interajam com dados escritos anteriormente (por exemplo, use uma coleção diferente para cada teste).
- Eliminar todos os dados escritos durante um teste.
A configuração do teste é muito complicada
Quando configurar o teste, pode querer modificar os dados de uma forma que as suas regras de segurança do Firestore não permitam realmente. Se as suas regras tornarem a configuração de teste complexa, experimente usar RulesTestEnvironment.withSecurityRulesDisabled nos passos de configuração, para que as leituras e as escritas não acionem erros PERMISSION_DENIED.
Depois disso, o teste pode realizar operações como um utilizador autenticado ou não autenticado, respetivamente, através de RulesTestEnvironment.authenticatedContext e unauthenticatedContext. Isto permite-lhe validar se as suas regras de segurança do Firestore permitem / recusam diferentes casos corretamente.