Escrever um teste do Jest
Objetivos de aprendizagem
Após concluir esta unidade, você estará apto a:
- Escrever um teste para verificar sua configuração.
- Escrever um teste com falha e alterar seu componente para fazer com que seja aprovado.
- Identificar os comandos básicos do Jest.
- Explicar os ganchos do ciclo de vida.
Iniciar com um componente web do Lightning
Para testar um componente web do Lightning, precisamos primeiro ter um componente para testar.
Criar um componente web do Lightning
- No Visual Studio Code, abra a paleta de comandos ao pressionar Ctrl+Shift+P (Windows) ou Cmd+Shift+P (macOS).
- Insira
lightning web
. - Selecione SFDX: Criar componente web do Lightning.
- Digite
unitTest
como nome do novo componente. - Pressione Enter.
- Pressione Enter novamente para aceitar o padrão
force-app/main/default/lwc
.
Isso cria o diretório unitTest no diretório lwc com os arquivos de base iniciais.
Escrever um teste básico
Os testes do Jest são escritos, salvos e executados de modo diferente dos testes Jasmine ou Mocha escritos para o Lightning Testing Service para componentes do Aura. Os testes do Jest são apenas locais e são salvos e executados independentemente do Salesforce. Na verdade, você receberá um erro se tentar implantar os testes do Jest na sua organização do Salesforce. Embora os testes do Jest para componentes web do Lightning não sejam implantados na sua organização do Salesforce, certifique-se de submetê-los ao controle de versão junto com o próprio componente.
A pasta __tests__
Os arquivos de teste precisam ser separados dos outros arquivos de componente. Se não for criada automaticamente, crie uma pasta chamada __tests__ no nível superior da pasta do pacote do seu componente. Salve todos os testes deste componente dentro da pasta __tests__.
- No Visual Studio Code, clique com o botão direito no diretório
unitTest
e selecione Nova pasta. - Insira
__tests__
. - Pressione Enter.
Configure .forceignore
Compartilhe testes com outros membros da equipe ou sistemas ao submeter a pasta __tests__ ao controle de versão. Eles são uma parte valiosa de seu projeto e processo de integração contínua. Para evitar que eles sejam implantados no Salesforce, o arquivo .forceignore tem uma exclusão inserida para ele.
- Verifique se o arquivo
.forceignore
de seu projeto contém as exclusões a seguir. Caso contrário, adicione-as e salve o arquivo.# LWC configuration files **/jsconfig.json **/.eslintrc.json # LWC Jest **/__tests__/**
Criar um arquivo de teste do Jest
Nosso primeiro teste é simples. Temos uma função sum ()
que deve adicionar dois números que são transmitidos a ele como argumentos.
- No Visual Studio Code, clique com o botão direto no diretório
__tests__
e selecione Novo arquivo. - Insira
sum.test.js
. - Pressione Enter.
- Insira o código a seguir no novo arquivo de teste:
import { sum } from '../sum'; describe('sum()', () => { it('should add 1 and 2 returning 3', () => { expect(sum(1, 2)).toBe(3); }); });
- Salve o arquivo.
Executar o teste
- No Visual Studio Code, selecione Exibir e, em seguida, selecione Terminal. Isso abre um terminal no Visual Studio Code. O padrão do terminal é o diretório de nível superior do projeto atual.
- No terminal, execute o comando da unidade anterior a seguir:
npm run test:unit
- O teste falha devido à função de soma ausente.
Vejamos como solucionar a questão.
- No Visual Studio Code, clique com o botão direito no diretório
unitTest
e selecione novo arquivo. - Insira
sum.js
. - Pressione Enter.
- Insira o bloco de código a seguir no novo arquivo:
export function sum(x, y) { return x + y; }
- Salve o arquivo.
- No terminal, execute o teste novamente:
npm run test:unit
- O teste passa.
Parabéns! Você acabou de confirmar que o Jest está configurado e funcionando.
Vejamos o código de teste para conferir o que está acontecendo.
import { sum } from '../sum'; describe('sum()', () => { it('should add 1 and 2 returning 3', () => { expect(sum(1, 2)).toBe(3); }); });
- A linha 1 importa a função de
sum
exportada do arquivo sum JavaScript. - A linha 3 é o início do conjunto de testes do Jest. A função ou bloco
describe
é um conjunto de testes e aceita dois argumentos. O primeiro é a descrição da unidade que estamos testando, que geralmente está na forma de um substantivo. O segundo é uma função callback que contém um ou mais testes. Você também pode aninhar conjuntos de testedescribe
uns dentro dos outros para gerar maior clareza. - A linha 4 é o teste (
it
é um alias paratest
). A função ou blocoit
também aceita dois argumentos. O primeiro é outra descrição do que estamos esperando, geralmente começando com um verbo. Em seguida, uma função callback que constrói o teste e contém as asserções ou expectativas para o teste. - A linha 5 é a declaração
expect
que declara a condição de sucesso: que a funçãosum
adicionaria os dois argumentos, 1 e 2, e retornaria 3.toBe
é um dos muitos Jest matchers.
Adicione outra asserção com a linha a seguir logo após a linha 5:expect(sum(1, 2)).not.toBeGreaterThan(3);
- Adicionar
.not
e.toBeGreaterThan
garante que o número não seja maior que 3. Você pode adicionar outra declaração expect com.not.toBeLessThan(3)
.
Agora, para o teste de componente web do Lightning.
Os testes do Jest para um componente web do Lightning devem testar o comportamento de um único componente isoladamente, com dependências mínimas de componentes ou serviços externos.
Passe pelo processo novamente com um arquivo de teste unitTest
Esse teste verificará se uma propriedade está definida e se, quando adicionada ao DOM, exibirá o texto correto. O arquivo unitTest.test.js
foi criado com a pasta __tests__
quando o comando SFDX: Create Lightning Web Component foi executado.
- Substitua o código em
unitTest.test.js
pelo seguinte:import { createElement } from 'lwc'; import UnitTest from 'c/unitTest'; describe('c-unit-test', () => { afterEach(() => { // The jsdom instance is shared across test cases in a single file so reset the DOM while(document.body.firstChild) { document.body.removeChild(document.body.firstChild); } }); it('displays unit status with default unitNumber', () => { const element = createElement('c-unit-test', { is: UnitTest }); expect(element.unitNumber).toBe(5); // Add the element to the jsdom instance document.body.appendChild(element); // Verify displayed greeting const div = element.shadowRoot.querySelector('div'); expect(div.textContent).toBe('Unit 5 alive!'); }); });
- Salve o arquivo.
- No terminal, execute os testes novamente:
npm run test:unit
- Os testes falham com isso:
Test Suites: 1 failed, 1 passed, 2 total Tests: 1 failed, 1 passed, 2 total
Vejamos esse código de teste para ver quais são os requisitos antes de atualizar o código para obter um teste que seja aprovado.
- A linha 1 é nova. Ela importa o método
createElement
a partir da estruturalwc
. Só está disponível em testes. - A linha 2 importa a classe
UnitTest
do controlador JavaScript do componente. - A linha 4 inicia o bloco de conjunto de testes
describe
. - A linha 5 é um método de limpeza do Jest.
afterEach()
é um dos métodos de configuração e limpeza do Jest.afterEach()
é executado após cada teste no bloco describe em que ele se encontra. Esse métodoafterEach()
redefine o DOM no final do teste. O Jest não está executando um navegador quando os testes são executados. O Jest usa jsdom para fornecer um ambiente que se comporta como o DOM ou documento de um navegador. Cada arquivo de teste obtém uma única instância do jsdom, e as alterações não são redefinidas entre os testes dentro do arquivo. Uma prática recomendada é realizar uma limpeza entre os testes para que a saída de um teste não afete nenhum outro teste. Existem outros métodos de configuração e limpeza disponíveis. Verifique os recursos. - A linha 12 inicia o bloco de teste
it
. - A linha 13 é onde o método importado
createElement
é utilizado. Ele cria uma instância do componente e a atribui à constanteelement
. - A linha 16 contém o
expect
declarando que a variávelunitNumber
está definida como 5. Esse é o primeiro requisito para o qual estamos testando, queunitNumber
esteja definido como 5 primeiro. - Na verdade, a linha 18 adiciona o
element
à versão do jsdom dodocument.body
usando o métodoappendChild
. A chamada anexa o componente web do Lightning ao DOM e o renderiza, o que também significa que os ganchos do ciclo de vida connectedCallback() e renderedCallback() são chamados (mais sobre o assunto posteriormente). - A linha 20 usa o
querySelector
(um método de consulta DOM padrão) para pesquisar o DOM para uma marcadiv
. Useelement.shadowRoot
como o principal para a consulta. É uma API somente de teste que permite espreitar pelo limite de sombra para inspecionar a árvore de sombra de um componente. - Por fim, a linha 21 contém o
expect
vendo otextContent
da marcadiv
para declarar “Unidade 5 viva!”. Esse é o requisito final. Declarando que o texto está correto.
Para fazer o teste passar, é necessário adicionar código aos arquivos HTML e JavaScript do unitTest. Adicionaremos código para cumprir os requisitos.
- Clique no arquivo
unitTest.html
para abri-lo. - Substitua
unitTest.html
por:<template> <lightning-card title="Unit Status" icon-name="standard:bot"> <div class="slds-m-around_medium"> Unit {unitNumber} alive! </div> </lightning-card> </template>
- Salve o arquivo.
- Clique no arquivo
unitTest.js
para abri-lo e substituí-lo por:import { LightningElement, api } from 'lwc'; import { sum } from './sum'; export default class UnitTest extends LightningElement { @api unitNumber = sum(2,3); }
- Salve o arquivo e execute os testes:
npm run test:unit
- Todos os testes passam.
Testar atualizações de DOM assíncronas
Quando o estado de um componente web do Lightning é alterado, o DOM atualiza de forma assíncrona. Para garantir que seu teste aguarde as atualizações serem concluídas antes de avaliar o resultado, retorne uma Promessa resolvida. Para fazer isso, encadeie o resto do seu código de teste à Promessa resolvida. O Jest aguarda a conclusão da cadeia de Promessas antes de encerrar o teste. Se a Promessa terminar no estado rejeitado, o Jest falhará o teste.
- Abra
unitTest.test.js
. - Adicione este segundo teste após o último teste.
Nesse teste, queremos verificar se uma alteração de propriedade atualizará o texto no DOM.it('displays unit status with updated unitNumber', () => { const element = createElement('c-unit-test', { is: UnitTest }); // Add the element to the jsdom instance document.body.appendChild(element); // Update unitNumber after element is appended element.unitNumber = 6 const div = element.shadowRoot.querySelector('div'); // Verify displayed unit status expect(div.textContent).toBe('Unit 6 alive!'); });
- Salve o arquivo e execute os testes.
npm run test:unit
- Você receberá essa mensagem de falha:
Expected: "Unit 6 alive!" Received: "Unit 5 alive!"
O que está acontecendo? A declaração expect
está declarando que o div.textContext
deve ser “Unidade 6 viva”, mas ainda é “Unidade 5 viva!”. Para ver a mudança, precisamos esperá-la retornando uma Promessa
resolvida.
- Substitua a declaração
expect
com falha pelo seguinte, logo após o comentário// Verify display unit status
:expect(div.textContent).not.toBe('Unit 6 alive!'); // Return a promise to wait for any asynchronous DOM updates. Jest // will automatically wait for the Promise chain to complete before // ending the test and fail the test if the promise rejects. return Promise.resolve().then(() => { expect(div.textContent).toBe('Unit 6 alive!'); });
- Execute o teste usando o mesmo comando da última vez ou use uma das outras opções da seção Executar testes do Jest da unidade anterior.
- O teste passa.
Por enquanto, tudo bem. Você conta com três testes bem-sucedidos em dois conjuntos de teste. Em seguida, adicione um quarto teste para que, quando um campo de entrada for atualizado, você possa verificar se o status da unidade é atualizado. Para fazer isso, use um evento de mudança no campo de entrada.
- Abra
unitTest.test.js
, se ainda não estiver aberto. - Adicione uma linha após o último teste que você adicionou e adicione este terceiro teste ao conjunto:
it('displays unit status with input change event', () => { const element = createElement('c-unit-test', { is: UnitTest }); document.body.appendChild(element); const div = element.shadowRoot.querySelector('div'); // Trigger unit status input change const inputElement = element.shadowRoot.querySelector('lightning-input'); inputElement.value = 7; inputElement.dispatchEvent(new CustomEvent('change')); return Promise.resolve().then(() => { expect(div.textContent).toBe('Unit 7 alive!'); }); });
- Salve o arquivo e execute o teste para ver a mensagem de falha.
Você pode ver que apenas um teste foi executado e os outros dois foram ignorados.
Vamos verificar o que está sendo testado:
- As primeiras linhas devem ser familiares. Você está adicionando o UnitTest ao
document.body
e, em seguida, criando uma referência àdiv
. - A constante
inputElement
é definida com uma referência a um campo de entrada do Lightning. - Em seguida, o valor desse campo de entrada é definido como 7.
- Em seguida, usamos o
dispatchEvent
para acionar um evento com umCustomEvent
usando um tipo de evento de “mudança”. - A
Promessa
é familiar e só mudou para o valor do campo de entrada alterado.
Vamos atualizar o código para fazer com que seja aprovado. Para fazer isso, adicione o lightning-input
ao arquivo HTML e o método handleChange
ao controlador JavaScript.
- Abra
unitTest.html
. - Adicione o código a seguir dentro do
lightning-card
e antes dadiv
:<lightning-input label="Unit Number" value={unitNumber} onchange={handleChange} > </lightning-input>
- Salve o arquivo.
- Abra
unitTest.js
. - Adicione o código a seguir após a declaração
@apiunitNumber
:handleChange(event) { this.unitNumber = event.target.value; }
- Salve o arquivo e execute os testes.
- Os testes são aprovados devido ao elemento de entrada adicionado e manipulador de JavaScript.
Testar ganchos do ciclo de vida
Componentes web do Lightning têm um ciclo de vida gerenciado pela estrutura. A estrutura cria componentes, adiciona e remove-os do DOM e renderiza atualizações do DOM sempre que o estado de um componente muda. Existem vários métodos para interagir com o ciclo de vida.
O gancho do ciclo de vida connectedCallback()
é acionado quando um componente é inserido no DOM. O gancho do ciclo de vida disconnectedCallback()
é acionado quando um componente é removido do DOM. Um dos usos desses ganchos é registrar e cancelar o registro de ouvintes de eventos.
Dê uma olhada no código no lmsSubscriberWebComponent a partir do repositório de amostras do lwc-recipes para obter um bom exemplo.
A seguir, veremos como escrever testes do Jest para serviços de conexão.
Recursos
- Salesforce Blog: Teste de unidade dos componentes web do Lightning com Jest
- Guia do desenvolvedor: Escrever testes do Jest para componentes web do Lightning
- Guia do desenvolvedor: Ciclo de vida dos componentes web do Lightning
- Site externo: Jest: Conceitos básicos
- Site externo: Jest: Referência expect
- Site externo: Jest: Configuração e desmontagem
- Site externo: GitHub: salesforce/sfdx-lwc-jest
- Site externo: GitHub: trailheadapps/lwc-recipes
- Site externo: Wiki: Desenvolvimento guiado por testes