Engenharia de IA Aplicada à Programação Web
Aula 10 de 10
Navegar por módulos e aulas
  1. 01 Fundamentos da Web
  2. 02 JavaScript moderno
  3. 03 TypeScript, Git e qualidade
  4. 04 Angular
  5. 05 Node.js, NestJS e APIs
  1. 4.1 Introdução ao Angular e componentes
  2. 4.2 Templates, bindings e control flow
  3. 4.3 Composição, inputs e outputs
  4. 4.4 Serviços e injeção de dependência
  5. 4.5 Rotas, layouts e navegação
  6. 4.6 Formulários e validação
  7. 4.7 HTTP, APIs e RxJS
  8. 4.8 Signals e estado da interface
  9. 4.9 Interceptors, erros e acessibilidade
  10. 4.10 Testes, compilação e projeto final

Módulo 4 · Aula 4.10

Testes, compilação e projeto final

2 horas Oficina integradora Angular
Ver fonte Markdown

Identificação

  • Duração: 2 horas
  • Tipo: oficina integradora
  • Entrega: painel Angular testado, compilado, documentado e apresentável
  • Laboratório: ../exemplos/aula-4.10/index.html

Introdução

O que é um teste automatizado?

Teste automatizado é código que executa uma situação, observa o resultado e compara esse resultado com uma expectativa.

preparar cenário → executar comportamento → verificar resultado

Se a expectativa não for atendida, o teste falha e informa onde o comportamento divergiu. Ele pode ser repetido por uma pessoa, pelo editor ou por um servidor de integração contínua.

Teste prova que não existem bugs?

Não. Um teste comprova somente o comportamento e os cenários que ele verificou. Uma suíte ajuda a detectar regressões e aumenta a confiança, mas não substitui análise, acessibilidade, segurança, validação real nem observação em produção.

Testar é o mesmo que depurar?

Não. Testar detecta que o resultado não corresponde ao esperado. Depurar é investigar por que isso aconteceu. Um teste pequeno e com nome claro facilita essa investigação.

O que é uma suíte de testes?

É um conjunto organizado de casos relacionados. Podemos agrupar testes por serviço, componente ou comportamento.

describe("TaskStore", () => {
  it("counts only open tasks", () => { /* ... */ });
  it("keeps a valid selection after removal", () => { /* ... */ });
});

O que é Vitest?

Vitest é o executor de testes usado por padrão nos projetos Angular CLI atuais. Ele oferece funções como describe, it, expect e vi.fn. O Angular continua fornecendo TestBed, fixtures e utilitários para criar o ambiente da aplicação.

Projetos antigos podem usar Karma e Jasmine. Não reescreva testes apenas pelo nome da ferramenta; planeje uma migração consciente.

O que é compilação?

Compilação é o processo de transformar o código-fonte da aplicação em arquivos que um navegador ou servidor poderá entregar.

TypeScript + templates + CSS + assets
                ↓ ng build
      HTML + JavaScript + CSS otimizados

A compilação verifica compilação e produz artefatos. Ele não publica automaticamente, não cria banco MySQL e não garante que a API esteja disponível.

Compilação é igual a publicação?

Não. ng build cria a pasta de saída. Publicar significa enviar essa saída a um servidor, CDN ou plataforma e configurar domínio, HTTPS, cache e fallback de rotas.

Se compilou, funciona?

Não necessariamente. Uma aplicação pode compilar e ainda possuir link quebrado, contraste ruim, API incorreta, erro de autorização ou rota que falha ao atualizar a página. Testes e auditoria complementam a compilação.

Desenvolvimento e produção são iguais?

Não. ng serve prioriza desenvolvimento, mensagens detalhadas e recarga rápida. A configuração de produção aplica otimização, AOT, minificação, eliminação de código inutilizado e outras transformações.

O que será entregue nesta aula?

Concluiremos o painel Angular da Knowledge AI com evidências reproduzíveis:

código → testes → compilação → auditoria → documentação → apresentação

Objetivos

Ao final da aula, o aluno deverá conseguir:

  1. explicar teste automatizado, suíte, caso e expectativa;
  2. distinguir testes unitários, de componente, integração e ponta a ponta;
  3. aplicar Arrange, Act e Assert;
  4. testar funções puras e stores com signals;
  5. criar componentes com TestBed e ComponentFixture;
  6. verificar conteúdo e interação no DOM;
  7. substituir dependências de modo controlado;
  8. testar HTTP sem rede real;
  9. verificar interceptors isoladamente;
  10. interpretar cobertura sem transformá-la em objetivo vazio;
  11. executar ng test localmente e em CI;
  12. explicar e produzir uma compilação de produção;
  13. auditar budgets, source maps, segredos e rotas SPA;
  14. documentar, demonstrar e defender o projeto do módulo.

Pré-requisitos

  • Aulas 4.1 a 4.9 concluídas;
  • componentes, templates, serviços, Router, formulários, HTTP e signals;
  • noções de funções e testes do Módulo 3;
  • terminal e scripts npm;
  • HTML semântico e acessibilidade.

Pergunta orientadora

Que evidências demonstram que o painel está pronto para ser entregue e mantido?

Roteiro sugerido

Etapa Duração
Estratégia e anatomia dos testes 20 min
Serviços, stores e componentes 30 min
HTTP, interceptors e acessibilidade 25 min
Compilação, segurança e hospedagem 25 min
Auditoria e apresentação 15 min
Encerramento 5 min

1. Pirâmide de testes

              poucos testes E2E
          testes de integração/componente
        muitos testes unitários rápidos

Testes unitários isolam regras pequenas. Testes de componente combinam classe e template. Integrações verificam fronteiras controladas. E2E percorre o sistema como usuário. A proporção depende do risco, não de uma fórmula rígida.

2. O que testar primeiro

Priorize:

  • regras de negócio;
  • fluxos críticos;
  • validação e autorização visual;
  • transformação de dados externos;
  • estados de erro e vazio;
  • regressões já encontradas;
  • acessibilidade essencial de interações.

Não comece testando getters triviais enquanto um envio crítico não possui cobertura.

3. Arrange, Act, Assert

it("marks a task as done", () => {
  // Arrange
  const store = createStoreWith([{ id: 1, done: false }]);

  // Act
  store.toggle(1);

  // Assert
  expect(store.tasks()[0].done).toBe(true);
});

Separar as fases deixa intenção e falha mais claras.

4. Um teste deve contar uma história

Prefira:

should keep the selected task when it still exists

Evite:

test 1
works

O nome deve indicar condição, ação e resultado relevante.

5. Teste funções puras sem Angular

describe("filterTasks", () => {
  it("returns only unfinished tasks for the open filter", () => {
    const result = filterTasks(TASKS, "open");
    expect(result.every((task) => !task.done)).toBe(true);
  });
});

Se uma regra não depende de DI, template ou framework, um teste direto é menor e mais rápido.

6. Testando um serviço com TestBed

describe("TaskStore", () => {
  beforeEach(() => {
    TestBed.configureTestingModule({ providers: [TaskStore] });
  });

  it("derives the open count", () => {
    const store = TestBed.inject(TaskStore);
    expect(store.openCount()).toBe(2);
  });
});

TestBed cria um ambiente isolado de injeção. Reinicialize o estado entre casos para que a ordem de execução não altere resultados.

7. Testando signals

Leia a API pública e execute comandos reais:

const before = store.openCount();
store.toggle(1);
expect(store.openCount()).toBe(before - 1);

Evite testar detalhes internos do grafo. O contrato relevante é o valor observado.

8. Mock, stub, fake e spy

Dublê Finalidade
stub devolve respostas controladas
fake implementação simplificada funcional
spy registra chamadas e argumentos
mock termo amplo; muitas ferramentas combinam stub e spy

Use o menor dublê necessário. Dublês demais fazem o teste conhecer a implementação em vez do comportamento.

9. Substituindo uma dependência

const apiStub = {
  list: vi.fn().mockReturnValue(of(TASKS)),
};

TestBed.configureTestingModule({
  providers: [
    TaskStore,
    { provide: TaskApi, useValue: apiStub },
  ],
});

O teste controla a fronteira sem chamar servidor real.

10. O que é ComponentFixture?

Fixture conecta instância, template renderizado e ciclo de detecção de mudanças.

const fixture = TestBed.createComponent(TaskCard);
fixture.componentRef.setInput("task", TASK);
await fixture.whenStable();

Use fixture.nativeElement para observar o DOM que o usuário receberia.

11. Teste de componente standalone

beforeEach(async () => {
  await TestBed.configureTestingModule({
    imports: [TaskCard],
  }).compileComponents();
});

Componentes standalone entram em imports, não em declarations.

12. Verificando o DOM

it("renders the task title", async () => {
  const fixture = TestBed.createComponent(TaskCard);
  fixture.componentRef.setInput("task", TASK);
  await fixture.whenStable();

  const title = fixture.nativeElement.querySelector("h3");
  expect(title.textContent).toContain(TASK.title);
});

Teste resultado visível. Evite acoplar a seletores decorativos que mudam com o CSS.

13. Interação do usuário

it("emits the task id when the button is clicked", async () => {
  const fixture = TestBed.createComponent(TaskCard);
  fixture.componentRef.setInput("task", TASK);
  const emitted = vi.fn();
  fixture.componentInstance.completed.subscribe(emitted);
  await fixture.whenStable();

  fixture.nativeElement.querySelector("button").click();

  expect(emitted).toHaveBeenCalledWith(TASK.id);
});

O teste percorre template, evento DOM e output.

14. Não teste apenas “deve criar”

expect(fixture.componentInstance).toBeTruthy();

Esse smoke test encontra falhas básicas de criação, mas não comprova comportamento. Adicione casos que representem decisões reais.

15. Estado assíncrono

Teste loading, success, empty e error separadamente. Controle o tempo com ferramentas do runner ou Observables determinísticos; não dependa de setTimeout real e rede.

16. Testando HTTP sem rede

TestBed.configureTestingModule({
  providers: [
    TaskApi,
    provideHttpClientTesting(),
  ],
});

const api = TestBed.inject(TaskApi);
const http = TestBed.inject(HttpTestingController);
const result = firstValueFrom(api.list());

const request = http.expectOne("/api/tasks");
expect(request.request.method).toBe("GET");
request.flush(TASKS);

expect(await result).toEqual(TASKS);

O backend de teste captura a requisição e devolve uma resposta controlada.

17. Verifique requisições pendentes

afterEach(() => {
  TestBed.inject(HttpTestingController).verify();
});

Isso detecta chamadas inesperadas ou esquecidas.

18. Testando interceptors

Quando o teste configurar recursos do cliente, registre primeiro provideHttpClient e depois provideHttpClientTesting:

providers: [
  provideHttpClient(withInterceptors([correlationInterceptor])),
  provideHttpClientTesting(),
]

Teste um interceptor por vez quando possível.

19. Erro HTTP controlado

request.flush(
  { code: "INTERNAL_ERROR" },
  { status: 500, statusText: "Internal Server Error" },
);

await expect(result).rejects.toMatchObject({ status: 500 });

Nenhum servidor real precisa falhar para testar a interface de erro.

20. Testando acessibilidade essencial

Automatize verificações simples e mantenha revisão humana:

  • botão nativo com nome acessível;
  • label associado ao campo;
  • erro ligado por aria-describedby;
  • role="status" ou role="alert" correto;
  • foco no resumo quando planejado;
  • navegação completa por teclado;
  • contraste e zoom em auditoria visual.

Automação não consegue avaliar toda a experiência de tecnologia assistiva.

21. Testes frágeis

Sinais comuns:

  • dependem da ordem;
  • usam tempos reais arbitrários;
  • verificam métodos privados;
  • quebram ao renomear uma classe CSS;
  • reproduzem a implementação dentro da expectativa;
  • compartilham estado mutável;
  • usam rede ou data atual sem controle.

22. Executando os testes

ng test

No desenvolvimento, o modo observação repete os testes após alterações. Para uma execução única explícita:

ng test --no-watch --no-progress

Em CI, o ambiente normalmente ativa o comportamento não interativo.

23. Cobertura de código

ng test --coverage

Cobertura informa quais linhas, funções e ramos foram executados. Cem por cento não garante boas expectativas; baixa cobertura em fluxo crítico revela risco, mas a meta deve apoiar qualidade, não gerar testes vazios.

24. O que é CI?

Integração contínua é um processo automatizado que valida mudanças em cada push ou pull request.

instalar → formatar/verificar → testar → compilar → publicar artefato

O fluxo deve falhar quando uma etapa obrigatória falhar.

25. Compilação de produção

ng build

Por padrão, o CLI atual utiliza a configuração de produção, salvo customização do espaço de trabalho. Verifique o resultado no diretório configurado em outputPath.

26. O que a produção otimiza?

  • compilação AOT de templates;
  • bundling;
  • minificação;
  • tree shaking e eliminação de código morto;
  • CSS e assets;
  • remoção de recursos de desenvolvimento;
  • hashing e cache conforme configuração.

O artefato deve ser testado no modo em que será hospedado.

27. Budget de bundle

Budgets geram aviso ou erro quando o tamanho ultrapassa limites:

{
  "type": "initial",
  "maximumWarning": "500kB",
  "maximumError": "1MB"
}

Escolha limites baseados no produto e acompanhe regressões. Não aumente o teto sem investigar o crescimento.

28. Source maps

Source maps ajudam a relacionar código otimizado ao fonte. Maps ocultos ainda podem vazar se o servidor os publicar. Defina uma política de geração, armazenamento e acesso para observabilidade.

29. Variáveis de ambiente não são cofres

Qualquer valor incorporado ao bundle do front-end pode ser encontrado no navegador. URL pública e feature flag podem estar na configuração; senha MySQL, chave privada e segredo de API não podem.

Angular → apenas configuração pública
NestJS  → segredos do servidor
MySQL   → credenciais acessadas pelo back-end

30. Rotas na hospedagem

Uma SPA com Router precisa que o servidor devolva index.html para deep links:

/tasks/42 → servidor entrega index.html → Angular resolve /tasks/42

Sem fallback, atualizar uma rota válida pode produzir 404 do servidor.

31. base href

Se a aplicação for publicada em subdiretório, confirme o caminho base e os assets. Uma configuração incorreta pode carregar o HTML e falhar em scripts, estilos e rotas.

32. Cache e hashing

Arquivos com hash permitem cache longo porque um conteúdo novo recebe outro nome. O HTML principal costuma exigir política mais curta para apontar aos bundles atuais.

33. Lista de verificação de segurança do bundle

  • nenhum token real;
  • nenhuma senha ou conexão MySQL;
  • nenhum .env secreto copiado;
  • nenhum source map público por acidente;
  • nenhuma mensagem com stack trace ao usuário;
  • URLs de API corretas;
  • dependências e licenças revisadas;
  • CSP e headers decididos na hospedagem.

34. README reproduzível

O README final deve explicar:

  1. objetivo e público;
  2. funcionalidades;
  3. stack e arquitetura;
  4. requisitos;
  5. instalação;
  6. execução local;
  7. testes;
  8. compilação;
  9. configuração pública;
  10. decisões e limitações;
  11. acessibilidade;
  12. demonstração e licença.

35. Projeto final do módulo

O painel da Knowledge AI deve conter:

  • shell e navegação por rotas;
  • dashboard;
  • lista, filtro e detalhes de tarefas;
  • cadastro e edição validados;
  • componentes reutilizáveis;
  • serviço/store com signals;
  • integração HTTP tipada;
  • loading, empty, success e error;
  • interceptors e mensagens acessíveis;
  • testes essenciais;
  • compilação de produção;
  • documentação reproduzível.

36. Arquitetura final

Angular
├── páginas e layouts
├── componentes de apresentação
├── formulários e estado visual
├── stores e serviços
├── Router
├── HttpClient + interceptors
└── testes
        │ HTTP
        ▼
NestJS → Prisma → MySQL

O módulo entrega o front-end e contratos simulados. O back-end real será construído nos próximos módulos.

37. Roteiro de apresentação

Em cinco minutos:

  1. problema e usuário;
  2. fluxo principal;
  3. arquitetura e decisões;
  4. demonstração de sucesso;
  5. demonstração de erro e acessibilidade;
  6. testes e compilação;
  7. limitações e próximo passo.

Não percorra arquivos sem contexto; conte a história do produto e mostre evidências.

38. Laboratório guiado

Abra a auditoria final do painel.

Etapa 1 — Selecione o perfil da entrega

Compare uma entrega incompleta com o painel preparado.

Etapa 2 — Execute a suíte simulada

Observe testes de regra, store, componente, HTTP, interceptor e acessibilidade.

Etapa 3 — Execute a compilação simulado

Acompanhe typecheck, AOT, otimização, budget e geração do artefato.

Etapa 4 — Audite documentação e segurança

Marque critérios e veja como eles alteram a prontidão.

Etapa 5 — Corrija falhas

Use “Preparar entrega completa” e compare o novo resultado.

Etapa 6 — Gere o parecer

Leia bloqueios, evidências e recomendação de apresentação.

39. Sobre o laboratório estático

O laboratório ensina o fluxo de qualidade sem depender de um espaço de trabalho Angular instalado dentro do curso. Os testes e a compilação são simulações determinísticas; a pasta src/app contém exemplos Angular/Vitest equivalentes.

40. Erros comuns

Testar só caminho feliz

Falhas de rede, validação, vazio e permissão ficam sem evidência.

Confundir cobertura com qualidade

Linhas executadas podem não possuir expectativas úteis.

Mockar tudo

O teste deixa de verificar integrações importantes.

Usar produção real no teste

Resultados ficam lentos, perigosos e instáveis.

Publicar ng serve

Servidor de desenvolvimento não é a entrega otimizada de produção.

Colocar segredo em environment

O valor entra no bundle e fica público.

Esquecer fallback SPA

Rotas funcionam por clique, mas falham ao atualizar.

Não registrar comandos

Outra pessoa não consegue reproduzir teste e compilação.

41. Desafio individual

Produza um pacote de evidências com:

  • pelo menos oito testes relevantes;
  • teste de sucesso e erro HTTP;
  • teste isolado de interceptor;
  • teste de interação e semântica acessível;
  • relatório de cobertura interpretado;
  • compilação dentro do budget;
  • auditoria de segredos;
  • teste de deep link;
  • README reproduzível;
  • vídeo ou apresentação de cinco minutos.

42. Lista de verificação de conclusão

  • Distingo teste, compilação e publicação.
  • Escrevo testes com Arrange, Act e Assert.
  • Testo comportamento, não detalhes privados.
  • Sei usar TestBed e fixture.
  • Testo HTTP sem rede real.
  • Verifico estados de erro e acessibilidade.
  • Entendo cobertura e seus limites.
  • Gero uma compilação para produção.
  • Audito segredos, budget e source maps.
  • Documento e apresento o projeto.

43. Rubrica do projeto

Critério Pontos
Componentes, templates e composição 15
Rotas e formulários 15
Serviços, signals e estado 15
HTTP, interceptors e erros 15
Acessibilidade 10
Testes automatizados 15
Compilação, segurança e desempenho 10
Documentação e apresentação 5
Total 100

Para concluir, obtenha pelo menos 70 pontos e não possua bloqueio crítico de segurança, compilação ou acessibilidade.

44. Resumo

  • testes automatizados produzem evidências repetíveis;
  • Vitest é o runner padrão dos projetos Angular CLI atuais;
  • TestBed cria ambientes isolados para DI e componentes;
  • o backend HTTP de teste evita rede real;
  • cobertura mede execução, não qualidade da expectativa;
  • compilação transforma fonte em artefato otimizado;
  • publicação exige servidor, rotas, cache e segurança;
  • o projeto final precisa ser reproduzível e defendido tecnicamente.

45. Fontes oficiais

Próximo módulo

No Módulo 5, criaremos o back-end com Node.js e NestJS: ambiente de execução, módulos, controllers, providers, DTOs, validação e os primeiros endpoints reais da Knowledge AI.