---
title: "De Karma para Vitest no Angular: a config que realmente roda"
description: "O que o test target de Vitest do Angular v21 realmente é (uma linha), de onde vêm polyfills e styles, o install que tira o Karma, e as poucas opções que valem adicionar."
deck: "Depois de anos de `karma.conf.js`, um `test.ts` de bootstrap e um launcher de browser, a config de Vitest do Angular v21 é quase nada: uma linha no `angular.json`. [O `ng new` gera ela](https://angular.dev/guide/testing), o build target fornece o resto, e o jsdom roda os testes. Aqui está o que essa linha te dá, o que você adiciona, e o detalhe que explica por que o `fakeAsync` quebra."
author: "André Ramos"
url: "https://andreramos.dev/pt/angular/karma-to-vitest-angular-config/"
lang: "pt-BR"
type: "article"
---

# De Karma para Vitest no Angular: a config que realmente roda

> Depois de anos de `karma.conf.js`, um `test.ts` de bootstrap e um launcher de browser, a config de Vitest do Angular v21 é quase nada: uma linha no `angular.json`. [O `ng new` gera ela](https://angular.dev/guide/testing), o build target fornece o resto, e o jsdom roda os testes. Aqui está o que essa linha te dá, o que você adiciona, e o detalhe que explica por que o `fakeAsync` quebra.

## O test target inteiro é uma linha

Depois do Karma você espera um arquivo de config. Não existe. O test target inteiro de Vitest no `angular.json` é a linha do builder: `{ "builder": "@angular/build:unit-test" }`. Sem `vitest.config.ts`, sem `karma.conf.js`, sem `test.ts` de bootstrap pra manter.

O `ng new` no Angular v21 gera exatamente isso, mais um `tsconfig.spec.json` cuja única linha notável é `"types": ["vitest/globals"]`. É o que faz `describe`, `it` e `expect` funcionarem sem import. O runner usa jsdom por padrão. Esse é o setup inteiro.

Algumas docs mostram um target avançado carregando um `providersFile`. Isso é opcional, não o default. Comece pela linha única e adicione knobs só quando um teste precisar.

*O primeiro spec, na config padrão*

```ts
// O tsconfig.spec.json define "types": ["vitest/globals"], então describe, it
// e expect não precisam de import. O builder roda isso em jsdom por padrão.
describe('AppComponent', () => {
  it('cria', () => {
    const fixture = TestBed.createComponent(AppComponent);
    expect(fixture.componentInstance).toBeTruthy();
  });
});
```

## De onde vêm polyfills, styles e assets

A razão de o test target poder ser uma linha é que ele não redefine seu app. Ele reusa o `build` target do projeto (a configuração de development) para compilar o app sob teste. Então os `polyfills`, `styles` e `assets` que você define no `build` já estão valendo. Você não os repete no `test`.

Esse detalhe tem uma consequência que vale saber antes de escrever um único teste. Como os polyfills de build incluem `zone.js`, o zone.js é carregado nos testes também. Mas o runner do Vitest nunca envolve cada teste na zone de teste do Angular, então `fakeAsync`, `tick` e `waitForAsync` lançam o erro de ProxyZone. A config está certa. Os helpers de tempo é que precisam de reescrita, [um trabalho separado](/pt/angular/angular-vitest-fakeasync-proxyzone-error).

| Preocupação | Onde se configura |
|---|---|
| Test runner, jsdom, `tsconfig.spec.json` | O target `test` (`@angular/build:unit-test`) |
| `polyfills` (zone.js), `styles`, `assets` | O target `build` (development), reusado automaticamente |
| Providers globais, coverage, browser real | Opções opt-in no `test` (abaixo) |

## O install: adicionar Vitest, tirar Karma

Migrar um projeto Karma existente é, na maior parte, cirurgia de dependência. Adiciona Vitest e jsdom, remove os pacotes de Karma e Jasmine, e aponta o target `test` pro builder de unit-test. O Angular 22 traz um schematic `migrate-karma-to-vitest` que automatiza a troca; os passos abaixo são o que ele faz por baixo, e o que revisar quando termina.

A primeira rodada é `ng test`. No CI, adicione `--no-watch`, já que o watch mode liga por padrão num terminal e desliga fora dele. Rode os specs simples primeiro e confirme que passam antes de tocar em qualquer coisa que mexa com tempo.

*De um projeto Karma a uma rodada Vitest verde*

```bash
npm install --save-dev vitest jsdom @vitest/coverage-v8
npm rm karma karma-chrome-launcher karma-jasmine karma-jasmine-html-reporter karma-coverage jasmine-core @types/jasmine
ng test --no-watch
```

## As opções que valem adicionar

Mantenha o target mínimo e adicione só o que um teste de fato precisa. Essas são as que mais aparecem, todas em `architect.test.options` para você não redigitar a cada rodada.

| Necessidade | Opção em `test.options` |
|---|---|
| Providers globais para todo teste (ex.: `provideHttpClientTesting`) | `providersFile` (o default export é um `Provider[]`) |
| Setup que roda depois dos polyfills e do TestBed | `setupFiles` |
| Coverage | `coverage: true` mais `coverageReporters` |
| Um browser real em vez de jsdom | `browsers` (precisa de `@vitest/browser-playwright`) |
| Sua própria config de Vitest para plugins | `runnerConfig` (o Angular carrega o arquivo mas não dá suporte ao conteúdo) |

## A config é a parte fácil

Se o target é uma linha, por que a migração leva uma tarde? Porque a config nunca foi o trabalho. O trabalho são os specs que quebram quando a test zone some: os testes de `fakeAsync` e `waitForAsync` que precisam de [uma reescrita para fake timers do Vitest](/pt/angular/angular-vitest-fakeasync-proxyzone-error). E antes de começar, vale decidir [se a migração compensa](/pt/angular/move-angular-test-suite-to-vitest) para uma suíte específica.

A config te dá um runner verde em uma linha. O resto do trabalho é manter ele verde.

## Artefato reaproveitável: Primeira rodada Vitest verde, vindo do Karma

- Adicione `vitest`, `jsdom` e `@vitest/coverage-v8` como devDependencies.
- Remova os pacotes de Karma e Jasmine (`karma*`, `jasmine-core`, `@types/jasmine`).
- Deixe o target `test` como uma linha de builder: `@angular/build:unit-test`.
- Confirme que o `tsconfig.spec.json` tem `types: ["vitest/globals"]`, para `describe`/`it`/`expect` não precisarem de import.
- Rode `ng test --no-watch` e deixe os specs simples verdes antes de tocar nos testes de `fakeAsync`.
- Adicione `providersFile`, `coverage` ou `browsers` só quando um teste de fato precisar.

## Perguntas frequentes

### Preciso de um arquivo vitest.config.ts num projeto Angular?

Não, não para o setup padrão. O builder `@angular/build:unit-test` já traz defaults que funcionam (ambiente jsdom e `tsconfig.spec.json`). Você só adiciona uma config de Vitest pela opção `runnerConfig` quando precisa de plugins customizados, e o Angular carrega esse arquivo sem dar suporte ao conteúdo dele.

### Onde coloco providers globais de teste como provideHttpClientTesting?

Num `providersFile`: um arquivo TypeScript cujo default export é um `Provider[]`. Aponte o test target para ele com a opção `providersFile` e ele vale para todo teste, o mesmo papel que o antigo `test.ts` fazia para setup global.

### O runner Vitest do Angular usa um browser real?

Não, ele roda em jsdom por padrão. Adicione a opção `browsers` (que precisa de `@vitest/browser-playwright`) para rodar num browser headless real quando um teste precisar de layout real ou de uma API de browser que o jsdom não implementa.

### Por que o zone.js ainda está carregado se eu migrei para Vitest?

Porque o build de teste reusa os polyfills do seu target `build`, e o `zone.js` está neles. É também por isso que o `fakeAsync` lança o erro de ProxyZone no Vitest: o zone.js está presente, mas o runner não estabelece a test zone que esses helpers precisam.

### Como consigo coverage com o runner Vitest?

Defina `coverage: true` e `coverageReporters` (por exemplo `text` e `lcov`) nas opções de teste, ou passe `--coverage`. Ele usa o `@vitest/coverage-v8`, que você adiciona como devDependency.

## Fontes consultadas

- https://angular.dev/guide/testing
- https://angular.dev/guide/testing/migrating-to-vitest
- https://angular.dev/reference/configs/angular-compiler-options
- https://vitest.dev/guide
- https://vitest.dev/config
- https://blog.angular.dev/announcing-angular-v21-57946c34f14b

## Leia também

- [Quando migrar uma suíte Angular para Vitest](https://andreramos.dev/pt/angular/move-angular-test-suite-to-vitest/)
- [fakeAsync e o erro ProxyZone: consertando testes Angular no Vitest](https://andreramos.dev/pt/angular/angular-vitest-fakeasync-proxyzone-error/)
- [Escolhendo o test runner do Angular em 2026: Vitest, Jest ou Karma](https://andreramos.dev/pt/angular/choosing-an-angular-test-runner/)
