← Angular: componentes, reatividade e decisões de aplicação
09 / 10 · 65 MIN

Testar comportamentos e limites de integração

Interpretar testes de componentes, pedidos e navegação pela evidência que observam. Distinguir chamadas diretas, eventos DOM, dependências controladas e integração real, incluindo notificações em aplicações zoneless.

O ambiente faz parte da evidência

A documentação atual dos novos projetos Angular CLI usa Vitest com jsdom por omissão. O runner executa em Node e o DOM é simulado; isso permite testes rápidos, mas não demonstra automaticamente layout, acessibilidade, desempenho ou todas as APIs de um browser real.

Projetos existentes podem usar outro ambiente, incluindo Karma, que continua suportado. Ao ler um resultado, identifica a configuração que o produziu e o comportamento realmente observado. Não atribuas a uma suite de unidades a cobertura de integrações remotas que foram substituídas por doubles.

Criação, atualização e leitura do DOM

TestBed.createComponent cria um fixture, mas não garante a execução síncrona de todas as bindings. Uma leitura imediata pode encontrar texto ainda vazio. O exemplo aguarda fixture.whenStable antes de verificar o estado inicial e volta a aguardar após a interação que agenda uma atualização.

Esta espera deve acompanhar trabalho que Angular conhece; não é uma promessa genérica de conclusão de qualquer sistema externo. O teste precisa de configurar e observar as dependências que fazem parte do comportamento, mantendo separadas temporização de renderização e conclusão de operações remotas.

Chamada direta ou interação do utilizador

Atribuir input.value altera o elemento, mas não emite o evento que o listener espera. Para representar essa interação no exemplo, o teste atribui o valor, chama dispatchEvent com input e aguarda a atualização. Depois observa o signal e o texto derivado, verificando os dois lados da binding.

Chamar diretamente um método do componente pode ser adequado para uma regra isolada, mas não deteta um nome de evento incorreto no template. Escolhe o caminho conforme a hipótese que pretendes testar e evita afirmar cobertura de um caminho que foi saltado.

Dependências e erros que o teste pode esconder

Um serviço fornecido pelo componente pode ser diferente daquele que TestBed.inject encontra na raiz. Para observar a instância realmente usada, consulta fixture.debugElement.injector. Esta distinção é relevante ao substituir estado por um double e depois estranhar que a vista não muda.

NO_ERRORS_SCHEMA também tem um custo: permite ignorar elementos e atributos não reconhecidos. Pode ser uma escolha de isolamento, mas não prova que imports e bindings reais estão corretos. Se a finalidade é aceitar integração de template, conserva verificações capazes de detetar metadata e nomes incorretos.

Pedidos controlados e resultados de falha

provideHttpClientTesting instala um backend controlado. Quando também configuras funcionalidades através de provideHttpClient, coloca essa configuração antes do provider de teste. O cliente deve subscrever primeiro; depois expectOne encontra o pedido, o teste inspeciona método e URL completo, flush fornece a resposta e as assertions observam o consumidor.

Verify ajuda a identificar pedidos inesperados. Uma resposta de backend com status 503 e um erro de rede são cenários diferentes, que se representam pelas APIs apropriadas. Nenhum flush demonstra disponibilidade ou autorização de um servidor real.

Navegação deve ser observada no destino

RouterTestingHarness permite configurar rotas e navegar para componentes no contexto de teste. Aguarda a navegação e verifica o resultado, como URL, componente apresentado ou redirecionamento. Um mock que devolve sucesso para qualquer URL pode esconder defeitos que surgiriam no router real.

Inclui resultados de rejeição e falha quando pertencem ao contrato. O teste de um guard confirma comportamento local nas premissas configuradas; uma API que ignora autorização pode continuar vulnerável apesar de todos esses testes passarem.

Notificações em aplicações zoneless

Zoneless é o padrão documentado desde Angular 21. Angular decide atualizar vistas a partir de notificações como escritas em signals lidos pelo template, listeners ligados, setInput e markForCheck, incluindo o utilizado por AsyncPipe. Atualizações programáticas do modelo de formulários, como patchValue numa callback externa, alteram estado e emitem observables, mas não agendam automaticamente a atualização do componente.

Liga essas mudanças ao mecanismo apropriado. Um teste que força sempre a atualização pode esconder essa ligação em falta; o objetivo é observar o comportamento de notificação que a aplicação realmente usa.

// Reading example of a test file in an Angular CLI Vitest test environment.
// Interpret the assertions; running this file is not an assessment requirement.
import {Component, computed, signal} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {expect, it} from 'vitest';
@Component({
  selector: 'record-label', standalone: true,
  template: `<label>Record <input #entry [value]="value()"
    (input)="value.set(entry.value)"></label><p>{{ label() }}</p>`,
})
class RecordLabel {
  readonly value = signal('R7');
  readonly label = computed(() => this.value().trim().toUpperCase());
}
it('reflects a typed record label', async () => {
  TestBed.configureTestingModule({imports: [RecordLabel]});
  const fixture = TestBed.createComponent(RecordLabel);
  await fixture.whenStable();
  const host = fixture.nativeElement as HTMLElement;
  expect(host.querySelector('p')!.textContent).toBe('R7');
  const entry = host.querySelector('input')!;
  entry.value = ' r8 ';
  entry.dispatchEvent(new Event('input'));
  await fixture.whenStable();
  expect(fixture.componentInstance.value()).toBe(' r8 ');
  expect(host.querySelector('p')!.textContent).toBe('R8');
});
NA PRÁTICA

O exemplo verifica estado inicial e depois percorre alteração DOM, evento input, escrita do signal e texto derivado. Uma chamada direta a value.set poderia verificar a derivação, mas não confirmaria que o template liga o evento correto. O teste descrito depende do ambiente Angular CLI Vitest indicado; o excerto não constitui evidência de que tenha sido executado.

Armadilhas comuns

Ler DOM antes da atualização; alterar input.value sem emitir evento; recuperar o serviço do injector errado; esconder erros com NO_ERRORS_SCHEMA; afirmar sucesso do backend por flush; considerar jsdom equivalente a todos os browsers.

Tópicos relacionados: Formulários, validação e intenção do utilizador · HTTP, streams e aceitação de respostas · Renderização, hidratação e evidência de entrega

Leva esta ideia contigo

Um teste útil liga uma premissa controlada a um resultado observável e declara o seu âmbito. Inspeciona tanto os resultados esperados como comportamentos indesejados, e conserva a distinção entre simulação, integração local e funcionamento real.

Criar conta

Referência: Current unit-test environment · Angular 22; standalone components