teqo-backup/tests/int/cityReportSnapshot.int.spec.ts
Francisco Solla 321ac7b872
Some checks failed
Deploy / preflight (push) Has been cancelled
Deploy / verify (push) Has been cancelled
Deploy / deploy staging (teqo-staging) (push) Has been cancelled
Deploy / requeue when main advanced (push) Has been cancelled
Deploy / deploy production (teqo-1313) (push) Has been cancelled
feat(relatorio-cidade): foca o relatório na mobilização do 2º turno
A federal foi decidida em 04/10; o documento de cidade passa a servir
inteiro à eleição de Lula. Saem conta eleitoral/cadeira de Solla,
concorrentes e pré-candidatos, emendas e entregas (sem fetch do Portal
da Transparência no builder), acervo de falas, panorama regional e
sinais/demandas; demografia, economia e transporte ficam como contexto
da visita.

A página 1 vira só mobilização: KPIs oficiais do artefato TSE 2026
(Lula/Δ, X₁/X₂, Solla), papel determinístico da cidade, quem mobiliza,
movimento local do 2º turno, riscos e o painel "O que pedir e falar"
(pedido Lula 13; guardrail de votos em jogo no lugar do defeso).

O checklist cai de 10 para 8 itens (emendas_web e quem_investe saem;
relacao_campo/disputa_local reancorados no 2º turno); listas
preCandidates/investments/emendasIndicators saem do contrato (arquivos
antigos seguem aceitos em replay). O snapshot enxuga para rede +
conjuntura + demografia (cityReportTerritory.mjs removido).

Prova: unit 5.232 verdes, int do snapshot sem PII e sem os grupos
aposentados, lint/format/typecheck/knip limpos e rebuild da fixture de
Cruz das Almas (9 seções, 16 páginas contra 21, página 1 fechando sem
fallback).
2026-10-10 16:57:20 -03:00

91 lines
3 KiB
TypeScript

// @vitest-environment node
import type { Payload } from 'payload'
import { getPayload } from 'payload'
import { beforeAll, describe, expect, it, vi } from 'vitest'
// `loadMunicipalityElectoralBaseline` is wrapped in Next's `unstable_cache`
// (needs the Next server runtime). The snapshot only forwards its result, so
// stub the module exactly like `municipalityDossierData.int.spec.ts` does.
vi.mock('@/utilities/municipality/municipalityElectoralBaseline', () => ({
loadMunicipalityElectoralBaseline: vi.fn().mockResolvedValue(null),
}))
import config from '@/payload.config'
import { composeCityReportSnapshot } from '../../scripts/cityReportSnapshot.mjs'
import { installCampaignFixtures } from '../helpers/campaignFixtures'
let payload: Payload
const campaignFixtures = installCampaignFixtures({
getPayload: () => payload,
setPayload: (nextPayload) => {
payload = nextPayload
},
})
describe('city report snapshot (C163)', () => {
beforeAll(async () => {
payload = await getPayload({ config: await config })
})
it(
'composes the mobilization snapshot (network + conjuncture + demographics), no PII',
{ timeout: 30_000 },
async () => {
const fixtures = campaignFixtures()
const candidate = await fixtures.createCampaignUser('candidate')
const advisor = await fixtures.createCampaignUser('advisor')
const municipality = await fixtures.getMunicipality()
await fixtures.assignMunicipalityAdvisors(municipality, [advisor])
const contact = await fixtures.createContact()
const leadership = await fixtures.createLeadership({
contact: contact.id,
municipalities: [municipality.id],
})
const actor = { ...candidate, collection: 'campaignUser' as const }
const snapshot = await composeCityReportSnapshot({
payload,
actor,
slug: municipality.slug,
codeSha: 'test-sha',
database: 'localhost:5432/teqo_wt_test',
})
expect(snapshot.meta).toEqual(
expect.objectContaining({
readOnly: true,
codeSha: 'test-sha',
actorRole: 'candidate',
}),
)
expect(snapshot.municipality.slug).toBe(municipality.slug)
expect(snapshot.advisors.map((advisorRow: { name: string }) => advisorRow.name)).toContain(
advisor.name,
)
expect(snapshot.leaderships.totalCount).toBeGreaterThan(0)
const row = snapshot.leaderships.rows.find(
(leadershipRow) => leadershipRow.id === leadership.id,
)!
expect(row.name).toBe(contact.name)
expect('phone' in row).toBe(false)
expect('email' in row).toBe(false)
expect('contactID' in row).toBe(false)
expect(JSON.stringify(snapshot)).not.toContain(contact.phone)
// The retired mandate-era groups never enter the snapshot again.
for (const retired of [
'electoral',
'goal',
'signals',
'activities',
'speeches',
'demands',
'competitors',
]) {
expect(retired in snapshot).toBe(false)
}
},
)
})