Ambiente de teste

Conforme apresentado em O que são testes, os testes em JavaScript são basicamente apenas códigos que confirmamos que são executados com êxito, ou seja, sem gerar uma Error. No entanto, uma das maneiras por que essa definição é uma simplificação excessiva é que ela não considera onde o código é executado, o ambiente de teste dele.

O ambiente de teste pode ser considerado como dois componentes: o ambiente de execução usado para executar o teste (como o nó ou o navegador) e as APIs disponíveis.

Ambiente de execução

Os ambientes de execução como o Node ou ferramentas semelhantes, como Deno ou Bun, têm como objetivo oferecer suporte ao código JS do lado do servidor ou de uso geral. Os ambientes deles não incluem APIs que você pode esperar em um navegador, como criar e trabalhar com elementos DOM e HTML, nem qualquer conceito de componente visual ou destino de renderização (ou seja, ou seja, não apenas elementos, mas renderizar esses elementos visualmente com CSS para uma janela de visualização).

Dessa forma, esses ambientes de execução de uso geral vão falhar se você tentar, por exemplo, renderizar elementos do React para que possam ser testados, porque não há objetos document ou window disponíveis.

Por outro lado, se você executar os testes em um navegador, as APIs integradas que você pode esperar desses ambientes de execução podem não estar disponíveis sem o polyfilling ou algum trabalho extra. Um problema comum é algo como ler e gravar arquivos: simplesmente não é possível usar import { fs } from 'node:'fs'; em um navegador e ler um arquivo dessa maneira como parte de um teste.

Esse problema de API "Web" e "back-end" está um pouco fora do escopo dos testes, porque pode ser estranho ter uma base de código com partes do servidor e do cliente, mas está relacionado à ideia de escrever código testável, que será abordada novamente ao longo deste curso.

Testar a lógica algorítmica ou de negócios

Parte do código não vai exigir importações de nó ou navegador para funcionar e, portanto, para teste. Falaremos sobre isso mais tarde neste curso, mas estruturar a base do código de modo que a "lógica de negócios" pura seja separada da renderização ou do código específico do nó pode facilitar o teste.

Como um exemplo rápido, você pode ter uma função Node que lê e grava um arquivo do disco e o modifica no processo. Ao refatorar sua função para aceitar funções que executam a leitura e gravação do disco, você a tornou testável em qualquer lugar.

Nesse caso, é possível usar qualquer ambiente para testar o código, seja em um ambiente de execução do lado do servidor ou no navegador. No teste, você pode fornecer auxiliares que armazenam um arquivo virtual na memória ou retornam dados de marcadores. Esse tipo de auxiliar é bom para introduzir em um teste, porque não é importante verificar, por exemplo, se fs.writeFileSync funciona. Concentre-se em seu código e no que o torna único ou arriscado.

Emular APIs do navegador

Muitos frameworks de teste, como o Vitest, oferecem a opção de emular o ambiente de API do navegador sem precisar executar o navegador. O Vitest usa internamente uma biblioteca chamada JSDOM (link em inglês). Essa pode ser uma boa escolha para testes de componentes simples em que a sobrecarga do uso de um navegador é alta.

Um recurso comum de qualquer biblioteca de emulação é que, embora elas possam emular um navegador, como o DOM, elementos e cookies, elas não têm um componente visual. Isso significa que eles são uma maneira imperativa de trabalhar com elementos HTML e outros primitivos, mas não é possível renderizar a saída de uma imagem ou tela nem verificar a posição de um elemento em pixels na página.

Novamente, essa escolha pode ser adequada para testes de componentes, em que um componente representa um elemento do React, um componente da Web etc. Esses tipos de componentes normalmente criam e interagem com o DOM de maneira relativamente pequena, e um navegador emulado pode fornecer funcionalidade suficiente para confirmar que o componente funciona da maneira pretendida. A próxima seção inclui um exemplo de teste do componente React com o Vitest e o JSDOM.

A emulação de um navegador é uma prática bem estabelecida (o JSDOM foi lançado em 2014), mas sempre é diferente de usar um navegador real. Essas diferenças podem ser óbvias: por exemplo, o JSDOM não inclui um mecanismo de layout, então não há como verificar o tamanho de um elemento ou testar um gesto complexo, como deslizar. As diferenças também podem ser sutis e desconhecidas. Por isso, é melhor manter os testes baseados em JSDOM concisos, para que você tenha um tempo limite para o risco de qualquer comportamento desviar do que é real.

Controle um navegador real

A melhor opção é usar um navegador real para testar o código da forma como ele será exibido aos usuários. Na prática, os testes de ambientes de execução compatíveis com o navegador iniciam e controlam instâncias de um navegador real, mesmo que elas executem "start" no Node.js.

Controlar um navegador como parte de um teste significa que ele será aberto como seria para um usuário, permitindo que seu teste o controle carregando URLs, HTML e JS personalizados ou o que for necessário para realizar o teste. Você pode escrever o código para agir como um usuário, controlando o mouse ou digitando a entrada nas caixas de entrada.

Ferramentas modernas, como WebdriverIO ou Web Test Runner, podem controlar todos os principais navegadores e até mesmo executar várias instâncias ao mesmo tempo. Esses navegadores podem ser executados ao lado do executor de testes (por exemplo, no seu computador ou como parte de uma ação de CI) ou ser terceirizados para serviços comerciais externos que os executarão para você.

Bibliotecas de teste mais estabelecidas (incluindo Vitest e Jest) geralmente têm um modo de navegador, mas, como a origem delas é do Node.js, os modos de navegador geralmente são "fixados" e não têm recursos úteis. Por exemplo, o Vitest não pode simular importações de módulo no navegador, que é um primitivo avançado que usamos no exemplo da próxima página.

Na prática

À medida que a complexidade dos testes aumenta, usar um navegador real fica cada vez mais importante.

  • Para testes que usam nenhum ou poucos recursos do DOM, até mesmo recursos disponíveis no Node.js e ambientes de execução semelhantes, como fetch ou EventTarget, o ambiente não importa.
  • Para testes de componentes pequenos, o JSDOM pode ser adequado.
  • Testes maiores, como os testes completos, que podem simular um usuário que faz login e realiza uma ação principal, fazem sentido ser executados completamente em um navegador real.

Esta seção aborda a teoria e apresenta diferentes pontos de vista sobre onde executar os testes. Na prática, sua base de código geralmente usa muitas abordagens diferentes para diferentes tipos de teste, com base nas suas necessidades e no que as ferramentas de teste oferecem.

Teste seu conhecimento

Com quais recursos do navegador o jsdom da camada de emulação *não* é compatível?

O mecanismo de layout.
Como o JSDOM não é uma ferramenta visual, ele não pode ser usado para verificar a posição de um elemento na página, os atributos CSS resolvidos dele ou qualquer outra parte do layout de um site.
WebSocket
O JSDOM inclui o polyfill do WebSocket, então o código que o utiliza funcionará.
requestAnimationFrame
Com o flag `pretendToBeVisual`, o jsdom invoca o callback "animation" a 60 fps, mesmo que nada seja realmente desenhado.