Testando UIs

Esta seção descreve como os desenvolvedores testarão a base de código relacionada à UI.

Stack de testes

Todos os nossos testes de UI DEVEM ser feitos usando Jestarrow-up-right como o framework principal de testes com redux-saga-test-planarrow-up-right como a ferramenta de teste de sagas e react testing libraryarrow-up-right como ferramenta de teste de componentes UI. O código dos testes DEVE ser escrito usando Typescriptarrow-up-right e executado usando ts-jestarrow-up-right para ter suporte à verificação de tipos.

O que testar

  • Componentes UI

  • Sagas

  • Reducers

  • Selectors

  • Action creators

  • Funções utilitárias

Testando sagas

Sagas nos permitem lidar com efeitos colaterais permitindo criar geradores que tratam ações do redux. Uma das principais vantagens das sagas é sua testabilidade, já que os efeitos amplamente usados em sagas são altamente testáveis.

Esses handlers DEVEM ser testados usando redux-saga-test-planarrow-up-right, e o teste DEVE exercitar toda a execução, desde o handler do módulo inteiro (seu handler principal ou sagas) por toda a execução dos handlers que irão reagir à ação que vamos despachar. Essa abordagem torna os testes de sagas fáceis de construir e manter, e traz valor aos testes ao percorrerem o fluxo o máximo possível.

Os testes dos handlers DEVEM ser testados através de sua interação com os efeitos, principalmente com o put um, já que seu propósito é lidar com ações e produzir novas. A maioria dos testes certamente conterá um provide call, usado para mockar efeitos, uma ou múltiplas put calls, para verificar que os handlers disparam as ações conforme esperado e um único dispatch seguido por um run call para executar toda a saga até a conclusão.

O mock de recursos externos ao módulo que está sendo testado DEVE ser feito usando os providers do redux-saga-test-plan aproveitando os diferentes efeitos fornecidos pelo redux-saga. Efeitos como call, apply ou outros DEVEM ser usados sempre que possível quando uma função é chamada em um teste para permitir mocká‑los facilmente. Jest NÃO DEVE ser usado para mockar módulos ou funções.

O texto no describe e seus DEVE seguir estas diretrizes:

  • O describe principal de uma saga ou handler principal DEVE começar com when handling, indicando que o que será testado é um handler. Seguindo a when handling frase, uma descrição da ação (ou a intenção que a ação) a ser tratada DEVE ser escrita. Ex.: when handling the action that signals a successful fetch.

  • Describes internos diferenciarão contextos de execução, eles seguem as mesmas regras descritas na Describing and building context seção.

  • O its DEVEM descrever o que é esperado do teste, começando com um should put e a descrição das ações que devem ser put ao executar o handler.

Exemplo de sagas

Exemplo de teste de sagas

Testando reducers

Reducers são funções que recebem um state e uma action e retornam um novo state. Esse novo state PODE conter alterações programadas para ocorrer para a ação dada.

Os testes DEVEM variar os estados iniciais e os diferentes parâmetros da action a ser testada se necessário. As asserções DEVEM ser feitas sobre todo o estado retornado, já que uma action pode modificar qualquer parte do state inicial fornecido.

Ao reduzir uma action, DEVEMOS usar o action creator, tornando os testes mais fáceis de manter.

Para padronizar a forma como escrevemos describes e its:

  • Describes principais DEVEM começar descrevendo quais ações serão reduzidas usando a frase when reducing the action seguida por uma descrição da ação. NÃO DEVEMOS usar o tipo da action para descrever a ação a ser testada, pois o tipo pode mudar.

  • O its DEVEM descrever de forma clara como o state retornado mudou. Ex.: it should return a state with the error nulled and the fruits set.

Exemplo de reducer

Exemplo de teste de reducers

Testando selectors

Selectors são métodos que recebem um state e retornam uma seção desse state ou uma seção transformada do state.

Existem dois tipos de selectors, selectors memoizados e selectors normais ou comuns. Selectors normais ou comuns DEVEM ser testados como qualquer outra função unitária testada e selectors memoizados DEVERIAM ser testados usando o resultFunc ou a função que recebe as partes memoizadas do state e retorna o valor desejado.

Describes e its DEVEM ser escritos conforme descrito em Describing and building context seção.

Exemplo de Selectors

Exemplo de teste de selectors

Testando action creators

Action creators são responsáveis por criar as ações que mais tarde serão processadas nos reducers. Embora action creators geralmente sejam simples, ELES DEVEM ser testados para garantir que façam o que esperamos.

Describes e its DEVEM ser escritos conforme descrito em Describing and building context seção.

Exemplo de action creators

Exemplo de teste de action creator

Testando componentes ui

Para testar componentes UI estamos usando React Testing Libraryarrow-up-right. Estamos usando esta biblioteca em vez de outras opções como enzyme, pois ela nos permite testar componentes levando em conta como o usuário irá interagir com ele em vez da implementação em si. Não iremos interagir com instâncias de componentes React; em vez disso, interagimos com elementos do DOM na forma como são renderizados.

O que testar

O propósito deste teste de componentes ui é testar o comportamento do componente e como o usuário interage com ele. Em muitos casos pode haver componentes que estão conectados ao redux store para obter algumas propriedades e chamar algumas ações. Geralmente lidamos com isso criando um container arquivo separado que irá interagir com a store. Esses arquivos estão fora do escopo deste tipo de teste. Estamos testando como o componente se comporta com diferentes valores de props; não devemos nos preocupar com a origem desses valores (redux store, context, componente pai), mas sim com como eles impactam a renderização final.

Renderização

Cada teste deve começar chamando a função render. Isso irá renderizar não apenas o componente que estamos passando como parâmetro, mas também todos os filhos. Devemos evitar fazer isso na configuração do teste (beforeEach) pois pode causar problemas fazendo com que a árvore do DOM tenha mais componentes do que queremos. Devemos salvar o resultado em uma propriedade chamada screen. Fazer isso nos permitirá obter todas as propriedades necessárias no teste sem a necessidade de alterar constantemente a desestruturação.

Se o documento tiver múltiplos testes e o componente tiver múltiplas props, podemos criar uma função no topo do arquivo que cuidará de definir props padrão e renderizar o componente.

Queries

Queries são os métodos que a Testing Library fornece para encontrar elementos na página. Existem diferentes tipos de queriesarrow-up-right que podemos usar para acessar os elementos. Devemos tentar sempre usar as queries que são Accessible to everyone pois são as que refletem a experiência para todos os usuários (visual/mouse e com tecnologia assistiva).

Essas queries são getByRole, getByLabelText, getByPlaceholderText, getByText, getByDisplayValue. Se pudermos acessar o elemento usando essas queries, provavelmente significa que o componente não é acessível.

Testando eventos de usuário

Não poderemos acessar funções dentro do componente, então devemos imitar o comportamento do usuário que leva a essas funções serem chamadas. Para isso estamos usando userEvent library.

Depuração

Para depurar o teste e qual é o estado atual do DOM em um momento específico podemos usar debug função que é uma das propriedades retornadas ao chamar render

Exemplo completo de teste de componente ui

Estrutura de diretórios

Os testes DEVEM ser colocados ao lado dos arquivos ou módulos que eles irão exercitar, com o mesmo nome, mas com a extensão spec.ts em vez de ts.

Uma estrutura de arquivos DEVE ficar assim:

Atualizado