ADR-0014 Testes
Norma da empresa para testes — bun test para testes unitários, de componentes (happy-dom) e de integração (Postgres e Valkey reais em Testcontainers); Playwright para interações e end-to-end.
- Decisão
- bun test + Testcontainers; Playwright E2EEntregar e operar
- Estado
- Aceite
- Data
- Âmbito
- Predefinição da empresa para todas as novas apps
Ligações
Apoia-se em
Citado por
- 0006Runtime e toolchain
- 0008ORM / camada de queries
- 0015Observabilidade
- 0016CI/CD
- 0017Reverse proxy e TLS
- 0018Tabelas
- 0019Listas virtuais
- 0020Gráficos
- 0021Markdown
- 0022Realce de sintaxe
- 0024Atalhos de teclado
- 0025SDK de IA
- 0026Estrutura do projeto
- 0027Princípios de engenharia
- 0028Jobs em segundo plano e agendamento
- 0029Email transacional
- 0030Armazenamento de ficheiros e objetos
- 0033Autorização
- 0035Runtime e toolchain
- 0036Camada de API
Contexto
Seção intitulada “Contexto”O Bun (ADR-0035) inclui um test runner: bun test, com uma API compatível com Jest em bun:test, mocks, snapshots, cobertura, ambientes DOM por ficheiro e ficheiros em paralelo. Falta definir contra o que corre cada tipo de teste. (Alterado em 2026-11-13: este ADR escolheu primeiro o Vitest através do Vite+, com testes de componentes no browser mode do Vitest; o ADR-0035 moveu a toolchain para o Bun.)
A stack torna algumas coisas difíceis de simular:
- Postgres através do
Bun.SQL(ADR-0008): um substituto em processo exige outro driver, pelo que o caminho de ligação real ficaria por testar - Valkey guarda sessões, contadores de rate limit e filas de jobs (ADR-0009, ADR-0010, ADR-0028)
- Componentes Base UI (ADR-0011) dependem de foco, eventos de ponteiro e layout reais — popovers, menus, focus traps
- O comportamento de segurança vive em middleware: o rate limiter e a verificação CSRF correm em
src/start.tsantes de qualquer handler (ADR-0010, ADR-0013); só um teste através do servidor real os vê
Opções consideradas
Seção intitulada “Opções consideradas”Test runner
Seção intitulada “Test runner”bun test— incluído no runtime; sem pipeline de transformação para configurar;--parallelcorre ficheiros por vários núcleos- Vitest — corre sob o Bun desde a 1.4, e o seu browser mode é a melhor opção para testes de componentes; mas é um segundo runner, com configuração própria, ao lado do que o runtime já tem
Testes de componentes
Seção intitulada “Testes de componentes”1. bun test com happy-dom + Testing Library
Seção intitulada “1. bun test com happy-dom + Testing Library”Prós: o mesmo runner que todos os outros testes; rápido; a configuração documentada pelo Bun. Contras: sem layout, sem foco nem eventos de ponteiro reais — as interações do Base UI tornam-se instáveis ou exigem mocks, pelo que têm de ser testadas noutro sítio.
2. Vitest browser mode (provider Playwright)
Seção intitulada “2. Vitest browser mode (provider Playwright)”Prós: Chromium real; o Base UI comporta-se como em produção. Contras: um segundo test runner mantido só para componentes.
Base de dados dos testes de integração
Seção intitulada “Base de dados dos testes de integração”A. Testcontainers (Postgres + Valkey)
Seção intitulada “A. Testcontainers (Postgres + Valkey)”Prós: os mesmos motores, tags de imagem, migrações e driver da produção; constraints, transações e comandos Valkey comportam-se a sério. O testcontainers 12 tem módulos para ambos (@testcontainers/postgresql, @testcontainers/valkey), e corre um smoke test com Bun no seu CI.
Contras: precisa de Docker localmente e no CI; segundos de arranque por execução.
B. PGlite (Postgres em WASM)
Seção intitulada “B. PGlite (Postgres em WASM)”Prós: sem Docker, rápido.
Contras: precisa de drizzle-orm/pglite em vez do nosso driver, pelo que o pooling e o Bun.SQL nunca são exercitados; pré-1.0 (0.5.10); sem Valkey.
C. Mock da camada de dados
Seção intitulada “C. Mock da camada de dados”Prós: o mais rápido. Contras: SQL, constraints, migrações e transações nunca são testados — onde vive a maioria dos bugs de dados.
End-to-end
Seção intitulada “End-to-end”- Playwright (
@playwright/test1.64) — Chromium, Firefox e WebKit; paralelo por predefinição; corre em Bun desde a 1.4 Bun.WebView— automação de browser headless integrada, mas sem test runner, traces nem integração com axe- Cypress (16.x) — boa DX, mas uma segunda toolchain de browser ao lado do Playwright
Decisão
Seção intitulada “Decisão”bun test para testes unitários, de componentes e de integração — componentes em happy-dom, testes de integração contra Postgres e Valkey reais em Testcontainers — e Playwright para interações que precisam de um browser real e para end-to-end. Esta é a norma da empresa para todas as novas apps.
Em concreto:
-
Os imports vêm de
bun:test. Sem Vitest, sem Jest. Obunfig.tomldefine[test] root = "src", pelo que as specs Playwright eme2e/nunca são recolhidas -
Três scripts:
Script Comando Ficheiros Para testbun test --parallel --path-ignore-patterns '**/*.int.test.ts'*.test.ts,*.test.tsxLógica pura, schemas Zod, componentes test:intbun test/int.ts*.int.test.tsAcesso a dados, serviços de domínio, handlers de API test:e2ebunx playwright teste2e/*.spec.tsInterações, percursos, acessibilidade Os testes ficam junto do código que testam; as specs E2E vivem em
e2e/ -
Os testes de componentes correm em happy-dom, escolhido por ficheiro: um teste de componente começa com
// @vitest-environment happy-dom, um pragma que obun testrespeita, e todos os outros ficheiros correm sem DOM. Renderizar com@testing-library/react, agir com@testing-library/user-event. Os dados vêm de props ou de umQueryClientnovo preenchido comsetQueryData— um cliente por teste, nunca partilhado. Os testes de componentes nunca tocam na rede -
O comportamento de foco, teclado e ponteiro é um teste Playwright. Os compostos Base UI (menus, popovers, diálogos, focus traps) e os atalhos de teclado (ADR-0024) são testados no browser, contra a app em execução
-
Os Testcontainers arrancam uma vez por execução.
test/int.tsarranca o Postgres e o Valkey com as mesmas tags de imagem da produção, aplica as mesmas migrações Drizzle que a produção corre numa base de dados template, e depois correbun test --parallel int.testcom os detalhes de ligação no ambiente. Cada ficheiro de teste cria a sua própria base de dados a partir do template (CREATE DATABASE … TEMPLATE …), pelo que os ficheiros correm em paralelo sem partilhar linhas, e dá ao seu cliente Valkey um prefixo de chaves feito a partir do nome do ficheiro -
Manter os handlers finos para que a lógica seja testável. As regras de negócio vivem em módulos simples que recebem as suas dependências (base de dados, relógio, clientes externos) como parâmetros; as server functions e os handlers das rotas da API apenas fazem parse, autorizam e chamam esses módulos. Os testes de integração cobrem os módulos e chamam diretamente os handlers em
server/api/, com umRequeste o caller autenticado emcontext(ADR-0036) -
A autenticação nos testes passa pelo Better Auth, nunca por linhas inseridas à mão: os testes de integração criam utilizadores e sessões com
auth.api; o E2E inicia sessão uma vez por worker e reutiliza ostorageStatedo Playwright -
Sem chamadas reais a terceiros. O HTTP externo (fornecedores OAuth, APIs de pagamento e de email) é simulado com MSW 3 (
setupServerdemsw/node), iniciado comonUnhandledFrame: "error"para que um pedido sem mock falhe o teste -
O E2E corre o build de produção (
bun run build, iniciado pelowebServerdo Playwright) contra contentores Postgres e Valkey, para que a cadeia de middleware real corra. Cobrir os percursos críticos de cada produto, começando pelo registo e pelo início de sessão. Correr@axe-core/playwrightem todas as páginas que um percurso visita; violações graves e críticas falham o teste -
Cada app mantém seis testes de guarda para invariantes de que os ADRs anteriores dependem:
- um
POSTcross-site para uma server function é rejeitado (ADR-0013) - um pedido a
/api/v1/com um cookie de sessão e sem token recebe401(ADR-0036) - um endpoint de credenciais devolve
429comRetry-Afteracima do seu limite (ADR-0010) - um pedido sem sessão iniciada a uma server function privada é recusado (ADR-0013)
- nenhum span exportado contém a query string de um URL (ADR-0015)
- um
X-Real-Ipforjado enviado através do edge é ignorado (ADR-0017) — este corre contra staging, porque precisa do Traefik no caminho
- um
-
Cobertura com
bun test --coverage(coverageReporter = "lcov"), reportada no CI sem limiar percentual — os limiares recompensam testes triviais; os testes de guarda e a revisão decidem o que tem de ser coberto -
A integração no CI (ordem, cache, instalação de browsers, retries) pertence ao ADR de CI/CD (ADR-0016)
Os fatores decisivos: o runner que o runtime já inclui, testes que usam o mesmo driver Postgres, Valkey e middleware que a produção, cobertura em browser real onde importa, e testes de guarda que impedem que as decisões de segurança dos ADRs anteriores regridam em silêncio. Aceitamos precisar de Docker para as execuções de integração e E2E, e mover os testes de interação dos testes de componentes para o Playwright.
Consequências
Seção intitulada “Consequências”Mais fácil:
- Um runner para testes unitários, de componentes e de integração; sem configuração de testes além do
bunfig.toml - Os bugs de dados (constraints, migrações, transações, comportamento do
Bun.SQL) aparecem nos testes, não em produção - Os testes unitários e de componentes são rápidos e não precisam de Docker nem de browser
- Remover o middleware CSRF ou quebrar o limiter faz falhar um teste em vez de seguir para produção
Mais difícil:
- O Docker é necessário para
test:inte para as execuções E2E, localmente e no CI;bun run testcontinua sem Docker para ciclos rápidos - O happy-dom não tem layout nem foco reais: um teste de componente que passa prova menos, e os bugs de interação só aparecem na suite Playwright, mais lenta. Manter a lógica interativa fina e coberta aí
- O pragma do happy-dom tem o nome do Vitest; o Bun documenta-o, mas lê-se de forma estranha
- O próprio projeto do Playwright não suporta o Bun; se uma atualização o quebrar, correr o job E2E na imagem do Playwright
- O MSW 3 é novo (2026-09); os seus exemplos da v2 usam
onUnhandledRequest, agoraonUnhandledFrame - O
@axe-core/playwrighté MPL-2.0 — aceitável como dependência de desenvolvimento; não copiar o seu código-fonte para o repositório
Do que abdicamos: de um browser real para os testes de componentes, de testes de integração sem Docker e de uma meta de percentagem de cobertura. Aceite — um só executor, o que o runtime já traz, testes no driver e no middleware reais, e interações provadas no Playwright provam mais por minuto gasto. Os testes de regressão visual estão fora de âmbito; um produto que precise deles escreve o seu próprio ADR.

