import { statSync } from 'node:fs' import { join } from 'node:path' import { describe, expect, it } from 'vitest' import { FEDERAL_BASELINE_CANDIDATE_NUMBER, federalBaselineMunicipalitySlugs, getFederalCompetitiveRank, getMunicipalityFederalBaseline, } from '@/lib/bahiaElectionAggregates' import { BASELINE_TICKET_2022, ELECTION_YEAR_2022, HISTORICAL_SERIES_YEARS, } from '@/lib/electionResults' import { municipalityCatalog } from '@/lib/municipalityCatalog' const ARTIFACT_PATH = join(process.cwd(), 'src/lib/electionAggregates/bahia-federal-baseline.json') /** * Pins the committed election-aggregate artifact to the municipality catalog. * If either changes shape (new remodel, new TSE scope), regenerate with * `pnpm build:election-aggregates` — a drift here means the map would render * zeros silently. */ describe('election aggregates artifact', () => { it('covers exactly the municipality catalog slugs', () => { const artifactSlugs = new Set(federalBaselineMunicipalitySlugs()) const catalogSlugs = new Set(municipalityCatalog.map((entry) => entry.slug)) expect(artifactSlugs.size).toBe(catalogSlugs.size) for (const slug of catalogSlugs) { expect(artifactSlugs.has(slug)).toBe(true) } }) it('is generated for the baseline ticket candidate', () => { expect(FEDERAL_BASELINE_CANDIDATE_NUMBER).toBe(BASELINE_TICKET_2022.candidate.candidateNumber) }) it('has every historical year populated with plausible statewide totals', () => { for (const year of HISTORICAL_SERIES_YEARS) { let candidateTotal = 0 let validTotal = 0 for (const slug of federalBaselineMunicipalitySlugs()) { const baseline = getMunicipalityFederalBaseline(slug) const votes = baseline.votesByYear[String(year)] const valid = baseline.validVotesByYear[String(year)] expect(votes).toBeTypeOf('number') expect(valid).toBeTypeOf('number') expect(votes).toBeGreaterThanOrEqual(0) expect(valid).toBeGreaterThanOrEqual(votes > 0 ? 1 : 0) candidateTotal += votes ?? 0 validTotal += valid ?? 0 } // A statewide federal-deputy campaign always lands in the 5-7 digit range. expect(candidateTotal).toBeGreaterThan(10_000) expect(validTotal).toBeGreaterThan(candidateTotal) } }) it('returns an empty baseline for unknown slugs', () => { const baseline = getMunicipalityFederalBaseline('nao-existe') expect(baseline.votesByYear).toEqual({}) expect(baseline.validVotesByYear).toEqual({}) expect(baseline.campoFederalVotesByYear).toEqual({}) expect(baseline.federalTallyByYear).toEqual({}) expect(baseline.majoritarian2022).toBeUndefined() }) it('has campo federal votes + federal tally for every historical year (v2 fields)', () => { for (const year of HISTORICAL_SERIES_YEARS) { let campoTotal = 0 let tallyComparecimentoTotal = 0 for (const slug of federalBaselineMunicipalitySlugs()) { const baseline = getMunicipalityFederalBaseline(slug) const campo = baseline.campoFederalVotesByYear[String(year)] const tally = baseline.federalTallyByYear[String(year)] expect(campo).toBeTypeOf('number') expect(campo).toBeGreaterThanOrEqual(0) expect(tally).toBeDefined() expect(tally.comparecimento).toBeGreaterThanOrEqual(0) expect(tally.votosValidos).toBeGreaterThanOrEqual(0) campoTotal += campo ?? 0 tallyComparecimentoTotal += tally?.comparecimento ?? 0 } // The campo (PT + core-left partners) always outpolls Solla alone, and // turnout always dwarfs any single candidate's nominal votes. expect(campoTotal).toBeGreaterThan(10_000) expect(tallyComparecimentoTotal).toBeGreaterThan(campoTotal) } }) it('has 2022 majoritarian (presidente/governador #13) votes+tally for every municipality', () => { let presidentTotal = 0 for (const slug of federalBaselineMunicipalitySlugs()) { const baseline = getMunicipalityFederalBaseline(slug) const majoritarian = baseline.majoritarian2022 expect(majoritarian).toBeDefined() if (!majoritarian) continue expect(majoritarian.president.votes).toBeGreaterThanOrEqual(0) expect(majoritarian.governor.votes).toBeGreaterThanOrEqual(0) expect(majoritarian.president.comparecimento).toBeGreaterThanOrEqual( majoritarian.president.votes, ) presidentTotal += majoritarian.president.votes } expect(presidentTotal).toBeGreaterThan(10_000) // Sanity: the 2022 majoritarian slice must not silently regress to a // different election year (only 2022 is seeded/expected here). expect(HISTORICAL_SERIES_YEARS).toContain(ELECTION_YEAR_2022) }) it('has a plausible competitive placement per IBGE municipality (v3 field)', () => { const ibgeCodes = new Set(municipalityCatalog.map((entry) => entry.ibgeCode)) let placed = 0 for (const ibgeCode of ibgeCodes) { for (const year of HISTORICAL_SERIES_YEARS) { const placement = getFederalCompetitiveRank(ibgeCode, year) // Absent is legitimate: he took no votes in that municipality that // year (351/417 municipalities placed in 2014, 416/417 in 2022). if (!placement) continue placed += 1 expect(placement.rank).toBeGreaterThanOrEqual(1) expect(placement.candidates).toBeGreaterThanOrEqual(placement.rank) } } // A statewide campaign places in most municipalities in most years. expect(placed).toBeGreaterThan(ibgeCodes.size * 2) }) it('gives Salvador one whole-city placement, not one per zone municipality', () => { const salvadorZones = municipalityCatalog.filter((entry) => entry.kind === 'zona') const salvadorCodes = new Set(salvadorZones.map((entry) => entry.ibgeCode)) // The 19 zone municipalities share Salvador's IBGE code, which is why the // placement is keyed by code: "which place did he come in" only has an // answer for the whole city. expect(salvadorZones.length).toBeGreaterThan(1) expect(salvadorCodes.size).toBe(1) const [salvadorCode] = salvadorCodes expect(getFederalCompetitiveRank(salvadorCode, ELECTION_YEAR_2022)).not.toBeNull() }) it('has no placement for an unknown IBGE code', () => { expect(getFederalCompetitiveRank('0000000', ELECTION_YEAR_2022)).toBeNull() }) it('stays under the committed artifact byte budget', () => { const { size } = statSync(ARTIFACT_PATH) // v1 (votes + valid votes only) was ~96 KB; v2 adds campo votes, federal // tally and the 2022 majoritarian slice, measured at ~522 KB; v3 adds the // per-IBGE competitive placement, measured at ~613 KB — budget with // headroom, not a precise pin, so future fields don't require touching // this test. expect(size).toBeLessThan(700 * 1024) }) })