Modernizando os testes no angular: alternativas ao Karma e caminhos para a migração

Modernizando os testes no angular: alternativas ao Karma e caminhos para a migração
Nayanne Batista
Nayanne Batista

Compartilhe

Com o lançamento da versão 16 do Angular, o uso do Karma foi descontinuado. Mas o que isso significa na prática?

Com o Karma deixando de ser suportado, surgem várias questões: qual ferramenta de teste devemos adotar agora? Será necessário reescrever todos os testes existentes? E quanto à migração - ela é complexa? Existe compatibilidade retroativa com os testes já desenvolvidos?

Vamos explorar essas questões neste artigo para entender como está o cenário de testes no angular.

Depreciação do Karma

O angular é um framework que possui diversas ferramentas integradas para a criação, desenvolvimento e build das aplicações.

E com os testes não é diferente; durante muitos anos o angular utilizou em seus projetos as ferramentas Karma e Jasmine, por padrão, ou seja, não era necessário instalar nada e a aplicação já estava pronta para iniciar os testes.

O Karma é um executor de testes que possibilita a execução de testes de unidade em vários navegadores.

Devido à sua integração com o framework de testes Jasmine e sua capacidade de simular ambientes de navegador reais, tornou-se a escolha de muitas pessoas desenvolvedoras.

De acordo com a equipe do angular, a decisão de descontinuar o Karma foi motivada por várias razões, incluindo o peso e a complexidade adicionais que ele introduz no processo de teste, dificuldades na integração com sistemas de integração contínua (CI), e a evolução das necessidades da comunidade em busca de soluções mais leves e eficientes.

Mas se o karma foi depreciado, isso quer dizer que não é recomendado utilizar o Jasmine para testar nossas aplicações? Vamos descobrir!

Executor de testes vs framework de testes

O karma e o Jasmine são ferramentas com funções diferentes, enquanto o karma é um executor de testes, o Jasmine é um framework de testes. E qual a diferença entre eles?

Um executor de testes é responsável por executar os testes criados usando um framework de testes.

No caso do Angular, o Karma atuava como o executor que permitia a execução dos testes definidos no framework Jasmine em diferentes navegadores.

Enquanto o Karma cuidava da execução e do ambiente de teste, o Jasmine definia a estrutura dos testes, incluindo as asserções e a organização dos casos de teste.

Isso quer dizer que a tarefa do Karma era iniciar um navegador e incorporar os testes do Jasmine. Portanto, a descontinuação do Karma não significa que o Jasmine está descontinuado, ele poderá continuar sendo usado, porém com outra opção de executor de testes de navegador, o Web Test Runner.

Mas antes de explorar essa ferramenta, é importante entender que existem dois tipos de executores de testes, aqueles cuja execução ocorre em um navegador, como o karma, por exemplo, e outros cuja execução se dá no próprio terminal. Vamos entender mais sobre isso?

Banner promocional da Alura, com um design futurista em tons de azul, apresentando o texto

Para escolher as ferramentas mais adequadas é importante entender que existem diferenças entre a execução de testes no navegador e no terminal, o que pode influenciar a eficiência e complexidade dos testes.

Execução no navegador

Vantagens:

  • A simulação precisa do ambiente de produção: permite executar testes em um navegador real, simulando o ambiente onde a aplicação será executada.
  • Acesso completo ao DOM e APIs de navegador: facilita testes que dependem diretamente do DOM e de APIs específicas do navegador.

Desvantagens:

  • Maior tempo de execução: devido ao tempo necessário para carregar e inicializar um navegador, os testes podem ser mais lentos em comparação com a execução no terminal.
  • Complexidade na integração com CI/CD: a dependência de um ambiente gráfico pode complicar a integração dos testes automatizados com pipelines de CI/CD, que geralmente preferem execuções simplificadas em linha de comando.

Exemplo de teste utilizando Karma e Jasmine numa aplicação de organização de leituras, onde temos um serviço chamado LivroService:

livro.service.spec.ts

import { TestBed } from "@angular/core/testing";

import { LivroService } from "./livro.service"

describe('LivroService', () => {
  let service: LivroService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [LivroService]
    })
    service = TestBed.inject(LivroService);
  });

  it('should create the LivroService instance', () => {
    expect(service).toBeTruthy();
  })
})

Quando executamos o comando ng test no terminal, o navegador é aberto automaticamente mostrando o teste executado pelo karma:

Uma captura de tela de um navegador mostrando a execução de um teste de unidade bem sucedido utilizando karma na versão 6.4.3.

Execução no Terminal

Vantagens:

  • Tempo de execução mais rápido: execução de testes de forma rápida, utilizando um ambiente Node.js sem a necessidade de carregar um navegador completo.
  • Facilidade de integração com CI/CD: por ser executado em linha de comando, se integra facilmente com pipelines de CI/CD, facilitando automações e execuções rápidas e repetíveis.

Desvantagens:

  • Limitações no acesso ao DOM e APIs específicas do navegador: para testes que dependem fortemente de interações com o DOM ou APIs específicas do navegador, pode oferecer limitações de simulação.
  • Menos simulação do ambiente real: embora seja rápido e eficiente, não reproduz completamente o ambiente de execução final como um navegador real, o que pode ser uma limitação em casos específicos de testes.

Exemplo de teste utilizando Jest:

Terminal mostrando a execução de um teste de unidade bem sucedido utilizando Jest.

Opções para novos projetos

Como o Karma está depreciado, a equipe do Angular adicionou suporte experimental ao Jest e ao Web Test Runner na versão 16 e está trabalhando para integrar totalmente essas ferramentas no ecossistema em versões futuras.

Cada uma dessas ferramentas oferece abordagens distintas para a execução de testes, buscando melhorar a eficiência e a velocidade das suas aplicações.

Que tal conhecer essas opções para decidir qual usar em seus projetos a partir de agora?

Jest

O Jest é um poderoso framework de testes em JavaScript com foco na simplicidade. Funciona com projetos usando: TypeScript, Node, React, Angular, Vue e muito mais!

Aqui estão algumas razões pelas quais o Jest é uma escolha vantajosa para testar aplicações Angular:

  • Rapidez e eficiência: o Jest é conhecido por sua velocidade de execução. Ele otimiza o tempo de teste por meio de técnicas como execução paralela de testes e execução seletiva de testes modificados. Isso é particularmente benéfico em projetos Angular, onde o tempo de compilação e teste pode ser um desafio.

  • Integração perfeita com Angular: o Jest se integra perfeitamente com o ecossistema Angular. Ele suporta a sintaxe do TypeScript e oferece recursos avançados para testar componentes, serviços, pipes e outras estruturas do Angular.

  • Sintaxe simples e intuitiva: a sintaxe do Jest é simples e fácil de entender, o que reduz a curva de aprendizado para quem está começando a escrever testes em projetos Angular. Seus métodos de asserção são expressivos e ajudam a tornar os testes mais legíveis e fáceis de manter.

  • Mocking flexível: o Jest oferece recursos avançados de mocking que simplificam o processo de simular dependências externas em testes de unidade. Isso é especialmente útil em projetos Angular, onde os componentes frequentemente dependem de serviços externos e módulos.

Como o Jest é um framework de testes com executor integrado, ainda há as vantagens de facilidade de configuração: por combinar ambas as funções, a configuração inicial é simplificada e também apresenta poucos problemas de compatibilidade, já que todas as funcionalidades de teste e execução são fornecidas pela mesma ferramenta.

Exemplo de teste utilizando o Jest:

import { TestBed } from "@angular/core/testing";

import { LivroService } from "./livro.service"

describe('LivroService', () => {
  let service: LivroService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [LivroService]
    })
    service = TestBed.inject(LivroService);
  });

  it('should create the LivroService instance', () => {
    expect(service).toBeTruthy();
  })
})

A sintaxe do Jest e do Jasmine são bem semelhantes, porém há funções exclusivas em cada um dos frameworks.

Web Test Runner

Desenvolvido pela Modern Web, o Web Test Runner oferece uma alternativa baseada em navegador para execução de testes, prometendo uma abordagem moderna e eficiente para o desenvolvimento de testes.

Ele utiliza o esbuild para compilação rápida e suporta a execução de testes em múltiplos navegadores de forma simultânea.

Ele é particularmente adequado para testes que dependem de um ambiente de navegador realista e oferece integração simplificada com sistemas de CI/CD.

Embora a abordagem de execução de testes utilizando o Jest tenha muitas vantagens, a equipe do angular vê um valor considerável em executores de testes baseados em navegador, por isso adicionou suporte experimental ao Web Test Runner para substituir o karma e utilizá-lo junto com o Jasmine.

Exemplo de teste utilizando o Web Test Runner

Navegador mostrando o processo de building de um projeto angular. Uma nota contém o aviso de que o Web Test Runner está em suporte experimental e ainda não deve ser usado em produção.
Terminal mostrando a execução de um teste de unidade bem sucedido utilizando web test runner.

Como migrar do Karma

A configuração do ambiente de teste é crucial para garantir a qualidade do código. Com a depreciação do Karma e a crescente popularidade de outras ferramentas, é importante que saibamos como instalá-las para fazer essa migração.

Migrando para o Jest

Mesmo em versões mais recentes do angular, ainda temos várias configurações do Karma e também do Jasmine, que continuam presentes no projeto. Portanto, precisamos instalar o Jest e, posteriormente, desinstalar essas outras ferramentas que não utilizaremos mais.

No terminal integrado, digite o comando para instalar o Jest.

npm install jest @types/jest @angular-builders/jest --save-dev

Após pressionar "Enter", a ferramenta será baixada. Dependendo da velocidade da sua internet, pode demorar um pouco, mas, de maneira geral, é rápido.

Perceba que foi modificado o arquivo package-lock.json, adicionando o builder do Jest, na versão 29.7.0.

package-lock.json:

"devDependencies": {
    "@angular-builders/jest": "^17.0.3",
    "@angular-devkit/build-angular": "^17.0.3",
    "@angular/cli": "^17.0.3",
    "@angular/compiler-cli": "^17.0.0",
    "@types/jasmine": "~5.1.0",
    "@types/jest": "^29.5.12",
    "jasmine-core": "~5.1.0",
    "jest": "^29.7.0",
    "karma": "~6.4.0",
    "karma-chrome-launcher": "~3.2.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "~2.1.0",
    "typescript": "~5.2.2"
}

E, no package.json, também houve algumas modificações nas dependências.

package.json:

"devDependencies": {
    "@angular-builders/jest": "^17.0.3",
    "@angular-devkit/build-angular": "^17.0.3",
    "@angular/cli": "^17.0.3",
    "@angular/compiler-cli": "^17.0.0",
    "@types/jasmine": "~5.1.0",
    "@types/jest": "^29.5.12",
    "jasmine-core": "~5.1.0",
    "jest": "^29.7.0",
    "karma": "~6.4.0",
    "karma-chrome-launcher": "~3.2.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "~2.1.0",
    "typescript": "~5.2.2"
}

Esse passo a passo foi feito em um projeto angular na versão 17. Caso você esteja utilizando versões anteriores, o processo é semelhante, mas pode sofrer algumas variações. Fique atento!

Modificando configurações

Agora, precisamos modificar algumas configurações em vários arquivos, mas a boa notícia é que temos uma forma automática de fazer isso com o Schematic, que é um script que consegue adicionar, remover e modificar diversos arquivos para realizar essa configuração.

Vamos copiar também o comando do Schematic no terminal e pressionar "Enter".

ng add @briebug/jest-schematic

Ele vai perguntar se queremos, de fato, instalar esse schematic. Vamos digitar o "Y" para confirmar.

Terminado o download dos pacotes, foi criado um arquivo jest.config.js e foram modificados os arquivos angular.json, package.json e ts.config.spec.json.

Por exemplo, podemos conferir as modificações no angular.json. No lugar do Karma, adicionou-se o Jest e foram realizadas outras modificações também.

angular.json:

"test": {
    "builder": "@angular-builders/jest:run",
    "options": {
        "tsConfig": "tsconfig.spec.json",
        "assets": [
            "src/favicon.ico",
            "src/assets"
        ],
        "styles": [
            "src/styles.css"
        ],
        "scripts": []
    }
}

No package.json, Jasmine e Karma foram excluídos das dependências de desenvolvimento. Assim, não precisamos fazer isso tudo manualmente.

package.json:

"devDependencies": {
    "@angular-builders/jest": "^17.0.3",
    "@angular-devkit/build-angular": "^17.0.3",
    "@angular/cli": "^17.0.3",
    "@angular/compiler-cli": "^17.0.0",
    "@briebug/jest-schematic": "^6.0.0",
    "@types/jest": "^29.5.12",
    "jest": "^29.7.0",
    "typescript": "~5.2.2"
}

Além disso, o arquivo jest.config.js foi adicionado com algumas configurações.

jest.config.js:

module.exports = {
  preset: 'jest-preset-angular',
  globalSetup: 'jest-preset-angular/global-setup',
};

Esse código exporta um objeto de configuração para o Jest. A configuração preset permite que você utilize configurações predefinidas para diferentes tipos de projetos.

No caso do Jest, presets são conjuntos de configurações que facilitam a configuração inicial do Jest para diferentes frameworks ou bibliotecas.

O jest-preset-angular é um preset específico para projetos Angular. Ele configura automaticamente diversas opções necessárias para que o Jest funcione corretamente com o Angular, como transformadores de arquivos, mapeamentos de módulos e outras opções específicas do Angular.

A configuração globalSetup permite definir um script que será executado uma única vez antes de todos os testes.

Isso pode ser útil para realizar configurações globais necessárias para os testes, como inicializar ambientes de teste ou configurar dependências globais.

Já o jest-preset-angular/global-setup é uma função fornecida pelo preset jest-preset-angular.

Ela realiza algumas configurações globais específicas para projetos Angular, garantindo que o ambiente de teste esteja corretamente configurado antes da execução dos testes.

Normalmente, isso inclui configurações como inicializar o Angular testing module, entre outras coisas.

Desinstalando Karma e Jasmine

Agora, o próximo passo é desinstalar o Karma e o Jasmine, que talvez ainda estejam presentes no projeto com o seguinte comando:

npm uninstall karma karma-chrome-launcher karma-coverage-istanbul-reporter karma-jasmine karma-jasmine-html-reporter karma-coverage jasmine-core
rm karma.config.js
rm src/test.ts

Esses dois últimos comandos, rm karma.config.js e rm src/test.ts, servem para remover esses arquivos, mas talvez não estejam no seu projeto. Você pode executar esses comandos que, se os arquivos não existirem (nas novas versões do Angular, esses arquivos não vem mais por padrão), serão ignorados. E, caso existam, serão removidos.

Migrando para o Web Test Runner

Podemos utilizar o Jasmine (que já vem por padrão nos projetos angular) juntamente com o Web Test Runner (que substituirá o karma, sendo o novo executor de testes). Para instalá-lo, digite no terminal:

npm i -D @web/test-runner

Em seguida, abra o arquivo angular.json para alterar o builder para o Web Test Runner na seção de teste.

angular.json

"test": {
  "builder": "@angular-devkit/build-angular:web-test-runner"
}

E também podemos remover as dependências do karma, já que ele não será mais utilizado.

Configuração do Web Test Runner

De acordo com a documentação, o Web Test Runner pode ser configurado usando um arquivo de configuração chamado web-test-runner.config. Esse arquivo pode ter uma das seguintes extensões:

  • .js: pode ser um módulo ES ou CommonJS, dependendo da versão do Node.js e do tipo de pacote definido no seu projeto;
  • .cjs: indica um módulo CommonJS;
  • .mjs: indica um módulo ES.

Exemplo de configuração

Aqui está um exemplo simples de um arquivo de configuração:

export default {
  concurrency: 10, // Número máximo de testes que podem ser executados simultaneamente.
    nodeResolve: true, // Habilita a resolução de módulos no estilo Node.js.
   watch: true, // Habilita a observação de arquivos para reiniciar os testes automaticamente quando os arquivos mudam.
    rootDir: '../../', // Define o diretório raiz para resolução de módulos, útil em monorepos.
};

A definição completa da configuração do Web Test Runner mostra diversas opções disponíveis para utilizar, de acordo com a necessidade da sua aplicação.

A seguir temos um exemplo de como essas configurações podem ser utilizadas, mas lembre-se de adaptar para a realidade do seu projeto:

import { playwrightLauncher } from '@web/test-runner-playwright';

export default {
  files: 'src/**/*.spec.ts',
  browsers: [
    playwrightLauncher({ product: 'chromium' }),
    playwrightLauncher({ product: 'firefox' }),
    playwrightLauncher({ product: 'webkit' }),
  ],
  reporters: [
    'spec'
  ],
  testFramework: {
    config: {
      ui: 'bdd',
      timeout: '2000',
    },
  },
};

Entendendo as configurações

  1. files
files: 'src/**/*.spec.ts',

Essa configuração define quais arquivos de teste devem ser incluídos na execução. Aqui, está configurado para incluir todos os arquivos com a extensão .spec.ts dentro do diretório src e seus subdiretórios. Esses arquivos geralmente contêm os testes para o projeto.

  1. browsers
browsers: [
  playwrightLauncher({ product: 'chromium' }),
  playwrightLauncher({ product: 'firefox' }),
  playwrightLauncher({ product: 'webkit' }),
],

Essa configuração indica quais navegadores serão utilizados para executar os testes. Utiliza o playwrightLauncher para iniciar instâncias dos navegadores chromium, firefox e webkit. E com a ferramenta Playwright é possível testar em múltiplos navegadores com uma única configuração.

  1. reporters
reporters: [
  'spec'
],

Com essa configuração, podemos definir que tipo de relatórios de teste serão gerados. No exemplo, o formato spec vai gerar um relatório detalhado dos testes executados, que é útil para ver o progresso e os resultados dos testes em tempo real.

  1. testFramework
testFramework: {
  config: {
    ui: 'bdd',
    timeout: '2000',
  },
}

Com o testFramework, estamos configurando o framework de testes utilizado.

ui: 'bdd' define o estilo de interface para o BDD (Behavior Driven Development), que é uma “técnica que faz uso de testes automatizados para guiar o desenvolvimento de novas funcionalidades ou correção de bugs”.

timeout: '2000' define o tempo máximo permitido para cada teste. Aqui, está configurado para 2000 milissegundos (2 segundos). Se um teste não terminar dentro desse tempo, ele será considerado como falhado.

Compatibilidade retroativa

A equipe do Angular está sempre preocupada em manter a estabilidade do framework e a compatibilidade das ferramentas do ecossistema.

Atualmente, na versão 17 do angular, o karma ainda está totalmente funcional e suas funcionalidades ainda são suportadas, portanto seus testes ainda funcionarão como antes, porém recomenda-se a migração para utilização de ferramentas mais modernas.

Para que a migração do karma seja feita de forma tranquila, foi adicionado suporte experimental ao Web Test Runner e ele será integrado com o Jasmine no lugar do Karma para que a experiência de desenvolvimento dos testes seja bem parecida com a anterior.

Além disso, também há o comprometimento em oferecer suporte para migração automática dos testes do karma para o Web Test Runner através do ng update e essas features estão em desenvolvimento.

Conclusão

A depreciação do Karma abre espaço para novas ferramentas de teste mais modernas e eficientes.

Com o suporte experimental ao Jest e ao Web Test Runner na versão 16 do Angular, a migração de ferramentas antigas para novas opções se torna mais acessível e será cada vez mais fácil.

Jest se destaca pela sua integração fácil e performance, enquanto o Web Test Runner oferece uma abordagem baseada em navegador para quem necessita de testes nesse ambiente.

Portanto, a escolha da ferramenta ideal depende das necessidades específicas do seu projeto e das suas preferências pessoais ou do time.

Com o futuro suporte para migração oferecido pelo Angular e as novas opções disponíveis, você pode modernizar sua suíte de testes e garantir uma cobertura robusta e confiável do seu código.

Quer se aprofundar mais em Angular e em testes? Confira os seguintes conteúdos da Alura:

Bons estudos!

Nayanne Batista
Nayanne Batista

Nayanne (Nay) é uma paraibana arretada que fez transição de carreira para a TI depois de concluir um doutorado na área da saúde e ser professora no ensino superior. Graduada em Análise e Desenvolvimento de Sistemas, já atuou como Dev Frontend em projetos e hoje é Instrutora na Alura. Acredita completamente no poder transformador da educação e da tecnologia na vida das pessoas. Ama livros e café! :)

Veja outros artigos sobre Front-end