mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-14 17:43:04 +00:00
* docs(A6): freshness audit da #27 no plano de dobradinhas 2026 electionInsights.ts foi deletado no Pass 2 W4a (modulo puro novo), electionAlliances.ts nao nasce (campoParties + electionPartySpectrum ja carregam a taxonomia), questoes em aberto resolvidas (tiers, score, proporcionais, lockdown de lideranca), card na aba Eleicoes, overview da lista fora de escopo, cache election-tse com bust na conciliacao Fase 5. Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com> * feat(A6): insight de dobradinhas 2026 na aba Eleicoes do municipio Lista ranqueada de candidatos proporcionais que concorrem de novo em 2026 (runningAgain2026=sim) por geografia do municipio: score 0,6 alinhamento (campo 2026 + espectro Bolognesi) + 0,4 forca local normalizada pelo maximo do conjunto. Estado pendente ate a conciliacao pos-15/08; Solla excluido (referencia, nao parceiro); leitura derivada sem escrita; loader cacheado sob a tag election-tse como os irmaos; link para /campanha/dobradinhas como caminho de registro operacional. Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com> * test(A6): cobertura unit/int do insight + lease das colecoes eleitorais Unit: tiers (campo/espectro/falha-para-o-meio), score, ordenacao, empates, limite, zero votos. Int: pending2026 sem conciliacao (mesmo com votos locais), so adversarios, misto com exclusao de Solla/nao e geografia alheia. Lease advisory election-collections serializa os dois specs que tratam as colecoes eleitorais como test-owned (o import wipe-all apagaria as fixtures do novo spec no meio do assert, 48-way paralelo). Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com> * refactor(A6): fixes do /simplify (3 reviewers paralelos) P1: campo coalition morto removido do input/select/mapping (sem consumidor). P1: hooks do lease com timeout explicito de 120s nos dois specs eleitorais (o wait advisory passa dos 10s default do Vitest sob contencao — flake em ambas as direcoes). P2: sonda de conciliacao via payload.count (idioma da casa), desempate final por candidateNumber (ordem deterministica), geography como prop na secao (sem lookup duplicado), casing Dep. Federal/Estadual alinhado, marcador 1313 via BASELINE_TICKET_2022, entrada no CHANGELOG. Declinados com justificativa: zones como tupla nao-vazia (churn em tipo compartilhado por assert provada no catalogo) e early-start da promise antes do Promise.all (loader-dentro-do-Suspense e o idioma da casa; ganho so em cache frio). Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
238 lines
7.3 KiB
TypeScript
238 lines
7.3 KiB
TypeScript
// @vitest-environment node
|
|
|
|
import { getPayload, type Payload } from 'payload'
|
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
|
|
import { BASELINE_TICKET_2022 } from '@/lib/electionResults'
|
|
import { FEDERAL_ONLY_OFFICES } from '@/lib/electionResultsBuild'
|
|
import config from '@/payload.config'
|
|
import { buildImportBundles, importElectionBundles } from '@/utilities/electionResultsImport'
|
|
import {
|
|
acquireTestDatabaseLease,
|
|
ELECTION_COLLECTIONS_LEASE_KEY,
|
|
type TestDatabaseLease,
|
|
} from '../helpers/testDatabaseLease'
|
|
import {
|
|
loadTseFixtureResults,
|
|
loadTseFixtureResultsForYear,
|
|
TSE_FIXTURE_EXPECTED,
|
|
} from '../helpers/tseFixtures'
|
|
|
|
let payload: Payload
|
|
let electionCollectionsLease: TestDatabaseLease
|
|
|
|
const deleteAllElectionData = async () => {
|
|
for (const collection of [
|
|
'electionCandidateVote',
|
|
'electionTally',
|
|
'electionCandidate',
|
|
] as const) {
|
|
const existing = await payload.find({
|
|
collection,
|
|
depth: 0,
|
|
limit: 0,
|
|
pagination: false,
|
|
overrideAccess: true,
|
|
})
|
|
for (const doc of existing.docs) {
|
|
await payload.delete({
|
|
collection,
|
|
id: doc.id,
|
|
overrideAccess: true,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
describe('election results import', () => {
|
|
// The lease acquisition blocks until the other election spec finishes its
|
|
// whole file — far past the 10s default hook timeout under pool contention.
|
|
beforeAll(async () => {
|
|
payload = await getPayload({ config: await config })
|
|
// This file deletes EVERY election row; the lease keeps that wipe from
|
|
// deleting another election spec's fixtures mid-run (48-way file
|
|
// parallelism, one Postgres).
|
|
electionCollectionsLease = await acquireTestDatabaseLease(
|
|
payload,
|
|
ELECTION_COLLECTIONS_LEASE_KEY,
|
|
)
|
|
await deleteAllElectionData()
|
|
}, 120_000)
|
|
|
|
afterAll(async () => {
|
|
await deleteAllElectionData()
|
|
await electionCollectionsLease.release()
|
|
}, 120_000)
|
|
|
|
it('imports fixture totals, winners, elected flags, and is idempotent', async () => {
|
|
const built = loadTseFixtureResults()
|
|
const bundles = buildImportBundles(built)
|
|
|
|
const first = await importElectionBundles(payload, bundles)
|
|
const second = await importElectionBundles(payload, bundles)
|
|
|
|
const firstVotes = first.reduce((sum, c) => sum + c.votesInserted, 0)
|
|
const secondVotes = second.reduce((sum, c) => sum + c.votesInserted, 0)
|
|
expect(firstVotes).toBe(TSE_FIXTURE_EXPECTED.voteRowCount)
|
|
expect(secondVotes).toBe(firstVotes)
|
|
expect(second.reduce((sum, c) => sum + c.votesDeleted, 0)).toBe(firstVotes)
|
|
|
|
const votes = await payload.find({
|
|
collection: 'electionCandidateVote',
|
|
depth: 0,
|
|
limit: 0,
|
|
pagination: false,
|
|
overrideAccess: true,
|
|
})
|
|
expect(votes.totalDocs).toBe(TSE_FIXTURE_EXPECTED.voteRowCount)
|
|
|
|
const sollaVotes = votes.docs
|
|
.filter(
|
|
(doc) =>
|
|
doc.office === 'deputado_federal' &&
|
|
Number(doc.candidateNumber) === BASELINE_TICKET_2022.candidate.candidateNumber,
|
|
)
|
|
.reduce((sum, doc) => sum + Number(doc.votes), 0)
|
|
expect(sollaVotes).toBe(TSE_FIXTURE_EXPECTED.sollaVotesTotal)
|
|
|
|
const tallies = await payload.find({
|
|
collection: 'electionTally',
|
|
where: {
|
|
and: [
|
|
{ office: { equals: 'deputado_federal' } },
|
|
{ cityCode: { equals: '38490' } },
|
|
{ zoneNumber: { equals: 1 } },
|
|
{ turn: { equals: '1' } },
|
|
],
|
|
},
|
|
depth: 0,
|
|
limit: 1,
|
|
overrideAccess: true,
|
|
})
|
|
expect(tallies.docs[0]?.winnerCandidateNumber).toBe(
|
|
TSE_FIXTURE_EXPECTED.federalWinnerSalvadorZ1.candidateNumber,
|
|
)
|
|
expect(Number(tallies.docs[0]?.winnerVotes)).toBe(
|
|
TSE_FIXTURE_EXPECTED.federalWinnerSalvadorZ1.votes,
|
|
)
|
|
|
|
const candidates = await payload.find({
|
|
collection: 'electionCandidate',
|
|
depth: 0,
|
|
limit: 0,
|
|
pagination: false,
|
|
overrideAccess: true,
|
|
})
|
|
const solla = candidates.docs.find(
|
|
(doc) => doc.office === 'deputado_federal' && Number(doc.candidateNumber) === 1313,
|
|
)
|
|
const lula = candidates.docs.find(
|
|
(doc) =>
|
|
doc.office === 'presidente' && Number(doc.candidateNumber) === 13 && doc.turn === '2',
|
|
)
|
|
const jeronimo = candidates.docs.find(
|
|
(doc) =>
|
|
doc.office === 'governador' && Number(doc.candidateNumber) === 13 && doc.turn === '2',
|
|
)
|
|
expect(solla?.elected).toBe(true)
|
|
expect(lula?.elected).toBe(true)
|
|
expect(jeronimo?.elected).toBe(true)
|
|
expect(lula?.identityKey).toBeTruthy()
|
|
})
|
|
|
|
it('imports a historical year without removing the 2022 scope', async () => {
|
|
const built2018 = loadTseFixtureResultsForYear(2018, FEDERAL_ONLY_OFFICES)
|
|
await importElectionBundles(payload, buildImportBundles(built2018))
|
|
|
|
const votes2022 = await payload.find({
|
|
collection: 'electionCandidateVote',
|
|
where: { year: { equals: 2022 } },
|
|
depth: 0,
|
|
limit: 0,
|
|
pagination: false,
|
|
overrideAccess: true,
|
|
})
|
|
const votes2018 = await payload.find({
|
|
collection: 'electionCandidateVote',
|
|
where: {
|
|
and: [{ year: { equals: 2018 } }, { office: { equals: 'deputado_federal' } }],
|
|
},
|
|
depth: 0,
|
|
limit: 0,
|
|
pagination: false,
|
|
overrideAccess: true,
|
|
})
|
|
const president2018 = await payload.find({
|
|
collection: 'electionCandidateVote',
|
|
where: {
|
|
and: [{ year: { equals: 2018 } }, { office: { equals: 'presidente' } }],
|
|
},
|
|
depth: 0,
|
|
limit: 0,
|
|
pagination: false,
|
|
overrideAccess: true,
|
|
})
|
|
|
|
expect(votes2022.totalDocs).toBe(TSE_FIXTURE_EXPECTED.voteRowCount)
|
|
expect(votes2018.totalDocs).toBeGreaterThan(0)
|
|
expect(president2018.totalDocs).toBe(0)
|
|
})
|
|
|
|
it('allows campaignUser read and denies campaignUser mutation', async () => {
|
|
// Avoid campaignFixtures here: teqo_test may already include territory migrations
|
|
// from other worktrees that diverge from this branch's electoralNucleus schema.
|
|
const campaignUser = await payload.create({
|
|
collection: 'campaignUser',
|
|
data: {
|
|
name: 'Election Access Tester',
|
|
role: 'coordinator',
|
|
email: `election-access-${Date.now()}@example.com`,
|
|
password: 'Password123!',
|
|
},
|
|
overrideAccess: true,
|
|
})
|
|
|
|
try {
|
|
const readable = await payload.find({
|
|
collection: 'electionTally',
|
|
depth: 0,
|
|
limit: 1,
|
|
user: campaignUser,
|
|
overrideAccess: false,
|
|
})
|
|
expect(readable.totalDocs).toBeGreaterThan(0)
|
|
|
|
await expect(
|
|
payload.create({
|
|
collection: 'electionTally',
|
|
data: {
|
|
year: 2022,
|
|
office: 'deputado_federal',
|
|
turn: '1',
|
|
state: 'BA',
|
|
cityCode: '99999',
|
|
cityName: 'Salvador',
|
|
zoneNumber: 99,
|
|
aptos: 1,
|
|
comparecimento: 1,
|
|
abstencoes: 0,
|
|
votosValidos: 1,
|
|
votosNominaisValidos: 1,
|
|
votosLegenda: 0,
|
|
votosBranco: 0,
|
|
votosNulo: 0,
|
|
votosAnulados: 0,
|
|
},
|
|
user: campaignUser,
|
|
overrideAccess: false,
|
|
}),
|
|
).rejects.toThrow()
|
|
} finally {
|
|
await payload.delete({
|
|
collection: 'campaignUser',
|
|
id: campaignUser.id,
|
|
overrideAccess: true,
|
|
})
|
|
}
|
|
})
|
|
})
|