feat(tests): suíte de integração LIVE para 82 edge functions + fuzz expandido + gate CI#380
Conversation
…xpandido + gate CI
- Harness tests/edge-functions/live/ (_live-client/_authz/_schemas/_live-suite)
dirigido pelo edge-authz-manifest + verify_jwt de config.toml.
- 1 spec por função (82/82) via descriptors.ts: CORS, fronteira de auth,
validação de input (sem-crash 5xx), contrato de erro {code|error|message}
e happy-path read-only/dry-run. Destrutivas em negative-only.
- describeLive faz skip sem credenciais (CI verde); roda LIVE com segredos.
- Fuzz: 8→20 endpoints (catálogo/busca/IA/webhooks) + imagem/uploads.
- Gate check:edge-live-coverage (bloqueia merge) + passos LIVE em ci.yml e
edge-integration-all.yml. Relatório de coverage por edge function.
- Docs: docs/testing/EDGE_LIVE_TESTS.md; .env.e2e.example atualizado.
https://claude.ai/code/session_01NKv93VdzWci9KLG98MMHNH
|
Warning Review limit reached
More reviews will be available in 19 minutes and 52 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (99)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Pull request overview
Este PR introduz uma suíte de testes de integração LIVE (HTTP real) para as Edge Functions do Supabase, com um harness comum, descritores por função e um gate de CI para garantir que toda função deployada tenha ao menos um teste LIVE correspondente. Também expande os scripts de fuzz e adiciona um relatório de “cobertura” por presença de testes por edge function.
Changes:
- Adiciona harness e gerador de suíte LIVE em
tests/edge-functions/live/+ registro central de descritores (descriptors.ts) e shims<fn>.test.ts. - Inclui gates e execução no CI (
check:edge-live-coverage+ job steps de LIVE) e documentação para rodar local/CI. - Expande fuzz para mais endpoints e gera relatório de cobertura por edge function em
coverage/edge-coverage-report.json.
Reviewed changes
Copilot reviewed 98 out of 98 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/edge-functions/live/_live-client.ts | Cliente HTTP LIVE com env detection, timeout e retry para chamadas às Edge Functions. |
| tests/edge-functions/live/_authz.ts | Derivação de expectativas de auth e classificação de funções destrutivas/dry-run. |
| tests/edge-functions/live/_schemas.ts | Schemas zod reutilizáveis para validar envelopes de erro e respostas. |
| tests/edge-functions/live/_live-suite.ts | Gerador da suíte padronizada (CORS, fronteira de auth, inválidos, happy-path). |
| tests/edge-functions/live/descriptors.ts | Registro central de inputs/happy-paths e casos inválidos por função. |
| tests/edge-functions/live/*.test.ts | Shims “1 arquivo por função” chamando runLiveSuite(descriptorFor(fn)). |
| scripts/check-edge-live-coverage.mjs | Gate de CI que falha se existir edge function sem shim LIVE. |
| scripts/gen-edge-live-tests.mjs | Scaffolder idempotente para criar shims LIVE por função. |
| scripts/generate-coverage-report.mjs | Emite relatório adicional de cobertura por edge function (presença de testes). |
| scripts/fuzz-testing.mjs | Expansão do fuzz (helper fieldFuzz + mais endpoints). |
| scripts/fuzz-edge-uploads.mjs | Adiciona fuzz de campos/URLs adversariais em funções de imagem/uploads. |
| package.json | Novos scripts test:edge:live* e check:edge-live-coverage. |
| .github/workflows/ci.yml | Integra gate + execução de LIVE (com skip sem segredos). |
| .github/workflows/edge-integration-all.yml | Integra gate + execução de LIVE (com skip sem segredos). |
| docs/testing/EDGE_LIVE_TESTS.md | Documenta como rodar e a política de segurança (negative-only/dry-run). |
| .env.e2e.example | Exemplo de vars para execução LIVE e tiers (E2E_*). |
| STATUS.md | Atualiza status com a sessão/entregáveis de testes LIVE. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let lastResult: EdgeResult | undefined; | ||
| for (let attempt = 0; attempt <= RETRY_COUNT; attempt++) { | ||
| const controller = new AbortController(); | ||
| const t = setTimeout(() => controller.abort(), opts.signalTimeoutMs ?? TIMEOUT_MS); | ||
| try { | ||
| const res = await fetch(url, { | ||
| method, | ||
| headers: finalHeaders, | ||
| body: rawBody, | ||
| signal: controller.signal, | ||
| }); | ||
| const text = await res.text(); | ||
| let json: unknown = null; | ||
| try { | ||
| json = text ? JSON.parse(text) : null; | ||
| } catch { | ||
| json = null; | ||
| } | ||
| lastResult = { status: res.status, headers: res.headers, text, json }; | ||
| if (!RETRY_STATUSES.has(res.status) || attempt === RETRY_COUNT) return lastResult; | ||
| } finally { | ||
| clearTimeout(t); | ||
| } | ||
| await sleep(RETRY_DELAY_MS * (attempt + 1)); | ||
| } | ||
| return lastResult!; | ||
| } |
| if (body !== undefined && body !== null && !("Content-Type" in finalHeaders)) { | ||
| finalHeaders["Content-Type"] = "application/json"; | ||
| } |
| interface InvalidInput { | ||
| label: string; | ||
| body?: Body; | ||
| headers?: Record<string, string>; | ||
| /** Role usado p/ passar a fronteira de auth antes da validação. */ | ||
| role?: EdgeRole; | ||
| } |
| /** | ||
| * Status aceitáveis para uma chamada ANÔNIMA (sem Authorization). | ||
| * - verify_jwt=false OU public/scoped: o handler é alcançado → qualquer não-5xx | ||
| * é válido (200 happy, 400/422 validação, 401 assinatura, 429 rate-limit…). | ||
| * O contrato relevante é "sem crash 500". | ||
| * - demais (gateway verify_jwt=true): gateway rejeita antes do handler → 401/403. | ||
| */ | ||
| export function expectedAnonStatuses(fn: string): { mode: "reject" | "reach" } { | ||
| if (VERIFY_JWT_FALSE.has(fn)) return { mode: "reach" }; | ||
| const cat = categoryOf(fn); | ||
| if (cat === "public" || cat === "scoped") return { mode: "reach" }; | ||
| return { mode: "reject" }; | ||
| } |
| import { z } from "zod"; | ||
|
|
||
| /** Contrato de erro padrão das edges migradas: { code, message, fields? }. */ | ||
| export const errorEnvelopeSchema = z | ||
| .object({ | ||
| code: z.string().optional(), | ||
| error: z.string().optional(), | ||
| message: z.string().optional(), | ||
| fields: z.array(z.string()).optional(), | ||
| }) | ||
| .passthrough() | ||
| // ao menos um identificador de erro presente | ||
| .refine((o) => Boolean(o.code || o.error || o.message), { | ||
| message: "erro sem code/error/message", | ||
| }); |
| "image-proxy": { | ||
| method: "GET", | ||
| query: "url=https://example.com/x.png", | ||
| invalidInputs: [{ label: "url ausente", body: undefined }], | ||
| }, |
| const res = await callEdge(fn, { | ||
| method, | ||
| query, | ||
| role: useRole, | ||
| headers: { ...baseHeaders, ...inv.headers }, | ||
| body: inv.body, | ||
| }); |
… + CI gate (#380) - Harness LIVE: 82/82 edge functions cobertas, 672 casos - CORS, auth boundary, inputs malformados, contrato {code|error|message} - Fuzz expandido: 8→20 endpoints, uploads/imagem - Gate CI: bloqueia merge se edge function sem teste LIVE - ESLint baseline atualizado (+3 any em useGlobalSearch.ts pré-existente)
…rava gate typecheck simpleQueries usa supabase.from(q.table) com tabela dinâmica (string), sem overload tipado → TS2769 (linha 417) + TS2345 em cascata (data como GenericStringError[]). Modela um SimpleQueryBuilder mínimo (eq/or/ilike/order/ limit) e remove os `builder as any` do bloco — sem any, runtime-idêntico. Elimina o drift legado da etapa 16 (STATUS.md) sem regressão de tipos/lint. https://claude.ai/code/session_01NKv93VdzWci9KLG98MMHNH
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
Conflitos resolvidos: - STATUS.md: PR #380 session (2026-05-26, edge LIVE tests) + sessão anterior do main mescladas - useGlobalSearch.ts: pega 'untypedFrom' helper do main (mais limpo que cast duplo as never)
|
Deployment failed with the following error: |
…tions) Conflitos resolvidos: - STATUS.md: mescla última sessão do PR com sessão anterior do main - src/components/search/useGlobalSearch.ts: pega 'untypedFrom' helper do main (mais limpo)
- useGlobalSearch.ts: remove type SimpleQueryBuilder orphan (ficou do PR #380 mas untypedFrom do main não o usa) - MockupGenerator.tsx: remove import Badge não usado - MockupGenerator.tsx: renomeia summary → _summary (definida mas não usada no JSX) ESLint baseline gate: ✅ zero regressões (drift positivo: -19 erros)
- useGlobalSearch.ts: remove type SimpleQueryBuilder orphan (ficou do PR #380 mas untypedFrom do main não o usa) - MockupGenerator.tsx: remove import Badge não usado - MockupGenerator.tsx: renomeia summary → _summary (definida mas não usada no JSX) ESLint baseline gate: ✅ zero regressões (drift positivo: -19 erros)
Contexto
A missão pedia testes de integração para cada Edge Function (validando entradas/saídas, erros e status codes), CI bloqueante, relatórios de cobertura e fuzz. O repositório já tinha E2E/CI/coverage/fuzz maduros; a lacuna real era que 62 das 84 edge functions não tinham teste algum e o fuzz cobria só ~8 endpoints. Por decisão do solicitante, os testes de integração são LIVE (HTTP real contra as funções deployadas), com foco no núcleo das edge functions.
O que muda
Harness LIVE (
tests/edge-functions/live/)_live-client.ts— fetch real com timeout + retry em 5xx;describeLivefaz skip silencioso sem credenciais (CI verde) e roda LIVE comVITE_SUPABASE_URL+VITE_SUPABASE_PUBLISHABLE_KEY; aquisição de JWT por role (E2E_USER/ADMIN/DEV_*)._authz.ts— deriva a fronteira de auth doedge-authz-manifest.ts+ doverify_jwtreal deconfig.toml; marca funçõesDESTRUCTIVE(negative-only) eSUPPORTS_DRY_RUN._schemas.ts(zod) +_live-suite.ts(gerador de suíte) +descriptors.ts(conteúdo por função).{code|error|message}e happy-path read-only/dry-run.Segurança
Funções com efeito externo (envio, sync, cleanup, reset de senha, logout global, bloqueio de IP, churn de chave) são negative-only — happy-path suprimido (exceto
dry_run). Validado contra o ambiente deployado: 672/672 passando, zero mutação.Fuzz expandido
fuzz-testing.mjs: 8→20 endpoints (catálogo, busca, IA, webhooks/orquestradores) via helperfieldFuzz.fuzz-edge-uploads.mjs: +analyze-logo-colors,visual-search,generate-mockup(URL/campo adversarial).CI & cobertura
check:edge-live-coverage(bloqueia merge se uma função deployada não tiver teste LIVE) + scaffoldergen-edge-live-tests.mjs.ci.yml(jobintegration-tests) eedge-integration-all.yml(skip sem segredos).generate-coverage-report.mjsagora emite seção por edge function (edge-coverage-report.json).docs/testing/EDGE_LIVE_TESTS.md;.env.e2e.exampleatualizado.Plano de teste
npm run check:edge-live-coverage→ 82/82 ✅npm run test:edge:livesem credenciais → 672 skipped (suíte verde)npm run test:edge:liveLIVE contra deployment → 672/672 passing (sem 5xx, sem mutação)node scripts/fuzz-testing.mjs(dry-run) → 761 payloads ✅ ·fuzz-edge-uploads.mjs→ 134 ✅npm run lint:baseline→ sem regressão de lintVITE_SUPABASE_*,E2E_*) para exercitar happy-pathsNotas
typecheckacusa drift pré-existente emsrc/components/search/useGlobalSearch.ts(etapa 16 adiada noSTATUS.md), não relacionado a este PR — nenhum arquivo desrc/foi tocado aqui.https://claude.ai/code/session_01NKv93VdzWci9KLG98MMHNH
Generated by Claude Code
Summary by cubic
Adiciona suíte de integração LIVE cobrindo 82 edge functions com HTTP real (CORS, auth, validação e contrato de erro), amplia o fuzz para 20 endpoints e cria um gate de CI por cobertura LIVE. Também ajusta a tipagem dinâmica em
useGlobalSearch, agora usando o helperuntypedFromdo main, destravando o gate de typecheck.New Features
tests/edge-functions/live/*(_live-client/_authz/_schemas/_live-suite) +descriptors.tse geradorscripts/gen-edge-live-tests.mjs— 1 spec por função (82/82), 672 casos.verify_jwt), inputs malformados sem 5xx e contrato{code|error|message}; happy-path só em rotas seguras/dry-run. Destrutivas em negative-only; caminhos caros viaEDGE_LIVE_COSTLY=1. Sem segredos,describeLivefaz skip; comVITE_SUPABASE_URL+VITE_SUPABASE_PUBLISHABLE_KEYroda LIVE (JWT por role via@supabase/supabase-js).fieldFuzz, incluindo uploads/imagem (analyze-logo-colors,visual-search,generate-mockup).CI & Coverage
check:edge-live-coverage(exigetests/edge-functions/live/<fn>.test.ts), passos LIVE em.github/workflows/ci.ymleedge-integration-all.yml. Scripts:test:edge:live,test:edge:live:coverage,scripts/check-edge-live-coverage.mjs.coverage/edge-coverage-report.jsonviascripts/generate-coverage-report.mjs. Docs emdocs/testing/EDGE_LIVE_TESTS.mde variáveis em.env.e2e.example.main: resolve conflitos e passa a usaruntypedFromemsrc/components/search/useGlobalSearch.ts(builder tipado, semany).Written for commit a894a4d. Summary will update on new commits. Review in cubic