Merge pull request #685 from fsolla/OPS39-prewarm-e2e-dev-adicionar-campanha-home-search-post-e-

OPS39 — Prewarm e2e: home-search POST e mudar-tendencia GET no setup spec
This commit is contained in:
Francisco Solla 2026-08-11 20:14:51 +00:00 committed by GitHub
commit b604157fc7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 115 additions and 0 deletions

View file

@ -0,0 +1,83 @@
# Impl: Prewarm e2e: adicionar /campanha/home-search (POST) e /campanha/acoes/mudar-tendencia (GET) ao setup spec
Status: aprovado
Atualizado em: 2026-08-11
Issue: #645
Intenção: docs/plans/prewarm-rotas-home-search-mudar-tendencia.md
Appetite restante: ~1 hora eng (herdado)
## Leitura da intenção
- **Outcome:** o `setup.e2e.spec.ts` preaquece as duas rotas que ficaram de fora,
para o 1º hit em dev não compilar no meio de um journey (B48/B97 flakearam 2/2
sob load ≥40 na sessão OPS36).
- **O que NÃO negociar:** setup continua em dev-mode-only, sem mudança de
asserções ou de CI; POST sem auth com `.catch(() => undefined)` — padrão das
entradas existentes.
- **O que reavaliar:** nada material — as rotas existem e o padrão do setup é
uniforme.
## Abordagem recomendada
```mermaid
flowchart LR
A[setup.e2e.spec.ts] --> B[GET /campanha/acoes/mudar-tendencia]
A --> C[POST /campanha/home-search]
```
**Opções consideradas:** A — duas linhas nas listas existentes | B — subir um
webServer `waitOn` prewarm
**Recomendação:** A — o setup spec já é o dono do prewarm dev; a intenção diz
"seguindo o padrão das entradas existentes". Custo ~2 linhas, zero risco.
**Rejeitadas:** B — duplica o mecanismo, fora do appetite.
### Componentes / mudanças
- **`tests/e2e/setup.e2e.spec.ts`**: na lista de GETs, adicionar
`/campanha/acoes/mudar-tendencia` ao lado de `/campanha/acoes/atualizar-votos`
(mesma família de wizard; GET anônimo → 307 para `/campanha/login`, seguido
pelo client → `response.ok()` true — mesmo contrato das entradas vizinhas).
Na lista de POSTs, adicionar `/campanha/home-search` (route handler em
`src/app/(campaign)/campanha/(app)/home-search/route.ts`; POST anônimo falha,
`.catch(() => undefined)` absorve — compila o handler, que é o objetivo).
- **Migration:** sem migration.
- **Access / Consent:** sem mudança — as rotas não são tocadas.
## Fases verificáveis
1. **Setup spec** — 2 linhas; gate rápido local.
2. **Gates** — `pnpm gate:fast` (ou lint/tsc); e2e direcionado: rodar o projeto
`setup` + B48 (`campaignMunicipalities` home-search) e B97
(`campaignHomeActions` mudar-tendencia) em dev a load ≥40, primeiro hit verde.
## Rabbit holes / Não escopo (engenharia)
- Hardening geral do prewarm em dev é dono da OPS30 (#586) — não reabrir aqui.
- Flakes de render sob carga em geral (B24, B176, demand) — fora.
## Riscos e mitigação
- GET `mudar-tendencia` sem auth poderia não compilar o bundle da página se o
redirect pular o render: mitigação — o GET segue o redirect (login), mas o
compile da rota `[slug]` acontece no primeiro match de rota, independente do
redirect; mesma família que `atualizar-votos` já prewarms com sucesso.
- Medição sob load ≥40 é cara: mitigação — verificação local direcionada
(workers ≥2, setup primeiro), sem CI novo.
## Desvio da intenção (aprovado 2026-08-11)
A intenção dizia "sem mudança de asserções ou de CI", mas o gate:ci falhou com
"No tests found" — **falha pré-existente do classificador** (OPS39 é a primeira
PR setup-only): o `setup` só existe em dev mode (projeto dropado sob `CI=1`,
playwright.config.ts OPS34), e `selectE2eSpecs` o selecionava sozinho para o
e2e prod-mode. Fix no dono (`scripts/lib/test-affected-core.mjs`): seleção
contendo **apenas** `setup` → `mode: 'none'` (spec dev-only; sets mistos seguem
inalterados — o spec simplesmente não casa projeto). 2 testes de unidade novos
em `tests/unit/testAffected.unit.spec.ts`.
## Aceite de engenharia
- [x] Aceite de produto da intenção ainda coberto
- [x] Invariantes AGENTS/engineering-standards (nenhum código runtime tocado)
- [x] Testes de domínio previstos (unit/int): 2 unit novos no classificador
(`testAffected.unit.spec.ts`); runtime intocado

View file

@ -232,6 +232,20 @@ export function selectE2eSpecs(files, manifest) {
unmapped,
}
}
// The `setup` spec is dev-mode-only: the setup project is dropped under
// CI/prod (playwright.config.ts), so a selection containing ONLY it would
// run `playwright test -- tests/e2e/setup.e2e.spec.ts` against zero projects
// and fail with "No tests found" (OPS39 — first setup-only PR hit it). In a
// mixed set the spec is harmless (it just matches no project), so only the
// setup-only case drops out.
if (specs.size === 1 && specs.has('setup')) {
return {
mode: 'none',
specs: [],
reason: 'setup spec is dev-mode-only; prod-mode e2e cannot run it',
unmapped,
}
}
return {
mode: 'selected',
specs: [...specs].sort(),

View file

@ -17,6 +17,7 @@ test('prewarms shared Next route bundles sequentially', async ({ request }) => {
'/campanha/liderancas',
'/campanha/conceitos',
'/campanha/acoes/atualizar-votos',
'/campanha/acoes/mudar-tendencia',
'/campanha/convite/e2e-prewarm',
'/',
]) {
@ -42,6 +43,7 @@ test('prewarms shared Next route bundles sequentially', async ({ request }) => {
'/campanha/webauthn/login',
'/campanha/webauthn/register-options',
'/campanha/webauthn/register',
'/campanha/home-search',
]) {
await request.post(`${baseURL}${path}`, { data: {} }).catch(() => undefined)
}

View file

@ -136,6 +136,22 @@ describe('selectE2eSpecs (OPS5)', () => {
const result = selectE2eSpecs([changed('docs/AGENT-OPS.md')], manifest)
expect(result).toMatchObject({ mode: 'none', specs: [], unmapped: [] })
})
it('drops a setup-only selection (setup runs only in dev mode, OPS39)', () => {
const result = selectE2eSpecs([changed('tests/e2e/setup.e2e.spec.ts')], manifest)
expect(result).toMatchObject({ mode: 'none', specs: [], unmapped: [] })
expect(result.reason).toContain('dev-mode-only')
})
it('keeps setup in a mixed selection (it matches no project, harmless)', () => {
const result = selectE2eSpecs(
[changed('tests/e2e/setup.e2e.spec.ts'), changed('src/app/(payload)/api/x.ts')],
manifest,
)
expect(result.mode).toBe('selected')
expect(result.specs).toContain('setup')
expect(result.specs).toContain('admin')
})
})
describe('e2eShardConfig (OPS34)', () => {