Pular para o conteúdo

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.ts antes de qualquer handler (ADR-0010, ADR-0013); só um teste através do servidor real os vê
  • bun test — incluído no runtime; sem pipeline de transformação para configurar; --parallel corre 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

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.

Prós: Chromium real; o Base UI comporta-se como em produção. Contras: um segundo test runner mantido só para componentes.

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.

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.

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.

  • Playwright (@playwright/test 1.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

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. O bunfig.toml define [test] root = "src", pelo que as specs Playwright em e2e/ nunca são recolhidas

  • Três scripts:

    Script Comando Ficheiros Para
    test bun test --parallel --path-ignore-patterns '**/*.int.test.ts' *.test.ts, *.test.tsx Lógica pura, schemas Zod, componentes
    test:int bun test/int.ts *.int.test.ts Acesso a dados, serviços de domínio, handlers de API
    test:e2e bunx playwright test e2e/*.spec.ts Interaçõ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 o bun test respeita, 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 um QueryClient novo preenchido com setQueryData — 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.ts arranca 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 corre bun test --parallel int.test com 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 um Request e o caller autenticado em context (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 o storageState do Playwright

  • Sem chamadas reais a terceiros. O HTTP externo (fornecedores OAuth, APIs de pagamento e de email) é simulado com MSW 3 (setupServer de msw/node), iniciado com onUnhandledFrame: "error" para que um pedido sem mock falhe o teste

  • O E2E corre o build de produção (bun run build, iniciado pelo webServer do 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/playwright em 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 POST cross-site para uma server function é rejeitado (ADR-0013)
    • um pedido a /api/v1/ com um cookie de sessão e sem token recebe 401 (ADR-0036)
    • um endpoint de credenciais devolve 429 com Retry-After acima 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-Ip forjado enviado através do edge é ignorado (ADR-0017) — este corre contra staging, porque precisa do Traefik no caminho
  • 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.

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:int e para as execuções E2E, localmente e no CI; bun run test continua 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, agora onUnhandledFrame
  • 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.