Português (Portugal)
  • teste
  • teste de e2e
  • teste de integração
  • desenvolvimento
  • produtividade
  • jest
  • puppeteer

Um guia rápido para escrever testes de ponta a ponta com jest-puppeteer

Este artigo fornece um guia rápido para escrever testes de ponta a ponta eficientes com jest-puppeteer, enfatizando o processo de configuração, as APIs mais comuns e cenários práticos de teste usando uma simples aplicação de lista de tarefas como exemplo.

Yijun
Yijun
Developer

Como parte do nosso compromisso em garantir a qualidade do Logto e melhoria contínua, utilizamos jest-puppeteer para testes automatizados de ponta a ponta. Isso nos permite iterar rapidamente no desenvolvimento do Logto sem interrupções.

Neste artigo, iremos compartilhar nossa experiência em escrever scripts de teste eficientes com jest-puppeteer, utilizando uma simples aplicação de lista de tarefas como exemplo. Nosso objetivo é ajudar você a começar rapidamente a escrever código de teste jest-puppeteer para os seus próprios projetos.

Introdução ao teste de ponta a ponta com jest-puppeteer

O teste de ponta a ponta é uma forma de garantir que a sua aplicação funcione corretamente do ponto de vista do usuário. Para conseguir isso, utilizamos duas ferramentas essenciais: Jest e Puppeteer.

Jest é uma popular framework de teste JavaScript que oferece uma API amigável para escrever testes e asserções. É amplamente utilizado para testes de unidade e integração.

Puppeteer é uma biblioteca Node.js desenvolvida pela equipe do Chrome que fornece uma API de alto nível para controlar navegadores headless Chrome ou Chromium. Isso o torna uma escolha ideal para automatizar interações com o navegador em testes de ponta a ponta.

jest-puppeteer é um preset do Jest que permite testes de ponta a ponta com Puppeteer. Ele oferece uma API simples para iniciar novas instâncias de navegador e interagir com páginas web através delas.

Agora que você tem uma compreensão básica das ferramentas essenciais, vamos nos aprofundar na configuração do seu ambiente de teste.

Configurando o seu ambiente de teste

Configurar o seu ambiente de teste para testes de ponta a ponta com jest-puppeteer é um processo simples que envolve três etapas principais:

  1. Instalar dependências

No seu projeto (ou crie um novo projeto), abra o terminal e execute:

Em seguida, vá para node_modules/puppeteer e instale o Chromium (que é necessário para o Puppeteer):

  1. Configurar o Jest

A seguir, você precisa configurar o Jest para funcionar perfeitamente com o Puppeteer.

Crie um arquivo de configuração do Jest (ex.: jest.config.js) na raiz do seu projeto, caso ainda não tenha um. Neste arquivo de configuração, especifique jest-puppeteer como preset:

Você pode personalizar outras configurações do Jest neste arquivo conforme necessário. Para mais informações sobre personalização das configurações do Jest, consulte a configuração do Jest.

  1. Escreva os seus testes

Crie arquivos de teste no seu projeto, geralmente com a extensão .test.js. O Jest irá automaticamente descobrir e executar esses arquivos de teste.

Aqui está um exemplo do documento do Jest:

Em seguida, execute o comando para rodar o teste:

Seguindo essas três etapas, você terá um ambiente de teste bem configurado para conduzir testes de ponta a ponta usando jest-puppeteer.

No entanto, observe que este é apenas um exemplo básico. Para obter mais informações detalhadas sobre a configuração do ambiente, consulte a documentação relevante:

APIs mais comuns

Nos próximos passos, vamos utilizar APIs fornecidas pelo Jest, Puppeteer e jest-puppeteer para nos ajudar em nossos testes.

O Jest oferece principalmente APIs para organizar testes e afirmar os resultados esperados. Você pode explorar os detalhes específicos na documentação.

As APIs do Puppeteer são projetadas principalmente para interagir com navegadores, e seu suporte para teste pode não ser tão direto. Você pode consultar a documentação do Puppeteer para entender as funcionalidades que ele oferece. Em nossos exemplos de teste subsequentes, iremos abordar alguns casos de uso comuns.

Como as APIs do Puppeteer não foram originalmente projetadas para testes, usá-las para escrever testes pode ser desafiador. Para simplificar o processo de escrever testes com Puppeteer, jest-puppeteer inclui uma biblioteca embutida chamada expect-puppeteer. Ela oferece um conjunto de APIs concisas e amigáveis. A biblioteca é detalhada na sua documentação, que apresenta várias funcionalidades úteis, como mostrado nos exemplos abaixo:

Nos exemplos a seguir, vamos combinar as APIs fornecidas por essas bibliotecas para completar nossos cenários de teste.

Agora é hora de começar a aprender como escrever código de teste usando nossa simples aplicação de lista de tarefas.

A simples aplicação de lista de tarefas

Supondo que temos uma simples aplicação de lista de tarefas rodando em http://localhost:3000, o código HTML principal para esta aplicação é o seguinte:

Ao conduzir testes de ponta a ponta, buscamos cobrir os seguintes cenários:

  1. Quando acessarmos o URL da aplicação, a aplicação e seus dados devem carregar corretamente.
  2. O botão de verificar do item deve ser clicável.
  3. Clicar em um link externo dentro das notas do item deve abrir o link em uma nova aba.
  4. Deve ser possível adicionar um item a partir do formulário.

Mais tarde, iremos escrever código de teste para validar esses cenários.

Esperar que a aplicação e seus dados tenham sido carregados

Consideramos que a aplicação foi carregada com sucesso quando as seguintes condições são atendidas:

  1. Um elemento com o ID "app" deve existir na página após acessar o URL da aplicação.
  2. Os dados dentro da aplicação devem ser renderizados corretamente.

Então, escrevemos o seguinte código de teste:

No código:

  • page.goto é equivalente a digitar "http://localhost:3000" no navegador, permitindo que você navegue para qualquer URL.
  • page.waitForSelector é usado para esperar que um seletor CSS específico corresponda a um elemento em particular, com um tempo de espera padrão de 30 segundos.
  • expect(page).toMatchElement é da biblioteca expect-puppeteer, sendo semelhante ao page.waitForSelector, mas também suporta correspondência do texto dentro de um elemento. Além disso, o tempo padrão para toMatchElement é de apenas 500ms.

Pode parecer perfeito à primeira vista, mas ao executar este teste e implantá-lo em um ambiente de CI, ele ocasionalmente falha após várias execuções. A mensagem de falha indica:

Com base nas informações de falha e o fato de que este teste passa na maioria das vezes, podemos inferir que os dados solicitados pela aplicação podem não retornar dentro dos primeiros 500ms após o carregamento da aplicação. Portanto, queremos esperar que os dados sejam carregados antes de fazer a asserção.

Normalmente, existem duas abordagens comuns para conseguir isso:

  1. Aumentar o tempo de espera da asserção

Pela mensagem de erro, podemos ver que o tempo de espera padrão para toMatchElement é definido como 500ms. Podemos aumentar o tempo de espera adicionando a opção timeout à função assim:

Esta abordagem pode reduzir a ocorrência de testes falhos em certa medida, mas não resolve completamente o problema porque não podemos saber com certeza quanto tempo é necessário para que os dados sejam buscados.

Portanto, usamos essa abordagem apenas quando temos certeza sobre o tempo de espera necessário, como em cenários como "um tooltip aparece após pairar sobre um elemento por mais de 2 segundos".

  1. Esperar pela conclusão da solicitação de rede antes de fazer a asserção

Esta é a abordagem correta. Embora não saibamos quanto tempo a solicitação de dados levará, esperar pela conclusão da solicitação de rede é sempre uma escolha segura. Neste ponto, podemos usar page.waitForNavigation({ waitUntil: 'networkidle0' }) para esperar que as solicitações de rede sejam concluídas:

Desta forma, antes de executarmos a asserção para a Aplicação e seus dados carregados, podemos garantir que nossas solicitações de rede já foram concluídas. Isso garante que o teste produza consistentemente os resultados corretos.

Esperar que um botão específico seja clicado

A seguir, estamos testando a funcionalidade de clicar no botão de verificar dentro de um item.

Na aplicação de exemplo, notamos que todos os itens compartilham a mesma estrutura. Os botões de verificar deles têm o seletor CSS li[class$=item] > button, e o texto do botão é sempre "Verificar". Isso significa que não podemos especificar diretamente qual botão de verificar do item clicar. Portanto, precisamos de uma nova solução.

Suponha que queremos clicar no botão de verificar do item "Ler o documento de início do Logto". Podemos quebrar isso em duas etapas:

  1. Primeiro, obtenha uma referência específica para esse item.
  2. Em seguida, clique no botão de verificar localizado dentro do item.

Como mostrado no código, utilizamos a função toMatchElement para corresponder ao item com o itemName definido como "Ler o documento de início do Logto". Em seguida, usamos a referência readDocItem para clicar no botão com o texto "Verificar" localizado embaixo dele.

É importante observar que ao obter readDocItem, o seletor CSS utilizado é li[class$=item]:has(div[class$=itemName]). Este seletor corresponde ao elemento li raiz do item, não ao itemName dentro dele, porque pretendemos clicar no button sob a tag li mais tarde.

O uso de expect(readDocItem).toClick é semelhante ao toMatchElement. No código de exemplo, passamos { text: 'Verificar' } para corresponder ainda mais ao textContent do botão. No entanto, você pode optar por corresponder ou não o conteúdo do texto do botão com base em suas necessidades.

A seguir, queremos testar se podemos abrir um link externo em uma nova aba ao clicar nele dentro das notas do item.

Na aplicação de exemplo, descobrimos que o item "Ler o documento de início do Logto" tem um link externo para o doc do Logto dentro das suas notas. Aqui está nosso código de teste:

No código, utilizamos toClick para clicar no link dentro de itemNotes.

Subsequentemente, usamos browser.waitForTarget para capturar uma nova aba aberta com o URL "https://docs.logto.io/docs/tutorials/get-started".

Após obter a aba, usamos target.page() para obter uma instância da página do doc do Logto e verificar se a página foi carregada.

Além disso, lembre-se de fechar a nova página aberta após concluir o nosso teste.

Esperar criar um item a partir do formulário

Agora, queremos testar a funcionalidade de adicionar um item.

Precisamos preencher o nome do item e as notas do item no formulário, clicar no botão "Adicionar" e verificar se o conteúdo que adicionamos aparece na lista:

Você notará que usamos a função expect(page).toFill(inputSelector, content) para preencher o conteúdo do formulário. Essa função substitui todo o conteúdo do input com o content.

Se você deseja adicionar alguns caracteres ao input sem substituir o conteúdo existente, você pode usar page.type(selector, content) para anexar diretamente o conteúdo desejado ao input.

No entanto, quando temos muitos campos para preencher no nosso formulário, chamar toFill várias vezes não é conveniente. Neste caso, podemos usar a seguinte abordagem para preencher todo o conteúdo em uma única chamada:

A chave do objeto fornecido é o atributo name do elemento input.

Resumo

Cobrimos um exemplo simples para introduzir requisitos comuns de teste e técnicas de escrita de código correspondentes ao usar jest-puppeteer para testes de ponta a ponta. Esperamos que isso possa ajudar você a rapidamente compreender o básico da escrita de código de teste jest-puppeteer.