teqo/tests/int/campaignMunicipalityScope.int.spec.ts
Francisco Ignácio Fontoura Solla 162d4c10fe perf(campanha): roda as funções em gru1 e encurta o waterfall de queries
As funções rodavam no default iad1 (Virgínia) enquanto o Neon fica em
sa-east-1 (São Paulo): cada query do Payload atravessava o equador duas
vezes (~120 ms por ida-e-volta) e uma página do /campanha faz uma dúzia.
Medido em produção: 410-470 ms de TTFB para um 307 que não toca o banco.

- vercel.json fixa regions: [gru1], mesma região AWS do banco (Hobby
  permite uma região, mas permite escolher qual).
- loadStatewideSuggestedGoals passa a ser exportada e é disparada dentro
  do Promise.all que já lê o escopo, na lista e no dashboard: o read do
  global campaignGoals saía sozinho no fim da requisição.
- loadMunicipalityScope lê os pledges em paralelo quando o ator é
  irrestrito e não há filtro (aí o IN de 435 ids não exclui nada);
  qualquer escopo mais estreito continua esperando os ids.

Débitos medidos no caminho e registrados em TECH-DEBT: o fan-out de
leituras do ator em getFreshCampaignUser (~5 por render) e a leitura
dupla em authenticateCampaignToken.
2026-07-26 21:00:06 -03:00

95 lines
3.7 KiB
TypeScript

// @vitest-environment node
import type { Payload } from 'payload'
import { getPayload } from 'payload'
import { beforeAll, describe, expect, it } from 'vitest'
import config from '@/payload.config'
import { loadMunicipalityScope } from '@/utilities/campaignMunicipalityScope'
import { installCampaignFixtures } from '../helpers/campaignFixtures'
let payload: Payload
const campaignFixtures = installCampaignFixtures({
getPayload: () => payload,
setPayload: (nextPayload) => {
payload = nextPayload
},
})
/**
* `loadMunicipalityScope` reads the pledge aggregate two different ways: an
* unrestricted actor with no filter holds the whole catalog, so both reads
* leave in one round trip with no `municipality IN (…)` narrowing; every
* narrower scope waits for the município ids. These pin that the two paths
* agree, and that the unfiltered shortcut stays out of reach of an actor whose
* scope is NOT the whole catalog.
*/
describe('loadMunicipalityScope', () => {
beforeAll(async () => {
payload = await getPayload({ config: await config })
})
it('aggregates the same pledge whether the scope is unfiltered or filtered', async () => {
const fixtures = campaignFixtures()
const coordinator = await fixtures.createCampaignUser('coordinator')
const municipality = await fixtures.getMunicipality()
const contact = await fixtures.createContact()
const leadership = await fixtures.createLeadership({
contact: contact.id,
municipalities: [municipality.id],
supportStatus: 'engajado',
})
await fixtures.createVotePledge({
leadership: leadership.id,
municipality: municipality.id,
declaredVotes: 80,
estimatedVotes: { pessimistic: null, central: 120, optimistic: null },
})
// Whole catalog: the unfiltered path, where the pledge read carries no id list.
const unfiltered = await loadMunicipalityScope(payload, coordinator, {})
// Same actor, narrowed by slug: the path that waits for the município ids.
const filtered = await loadMunicipalityScope(payload, coordinator, {
slug: { equals: municipality.slug },
})
expect(filtered.municipalities.map(({ id }) => id)).toEqual([municipality.id])
expect(unfiltered.pledgeAggregates.get(municipality.id)).toEqual(
filtered.pledgeAggregates.get(municipality.id),
)
expect(unfiltered.pledgeAggregates.get(municipality.id)).toMatchObject({
declaredTotal: 80,
pledgeCount: 1,
missingEstimateCount: 0,
})
expect(unfiltered.pledgeAggregates.get(municipality.id)?.effectiveByScenario.central).toBe(120)
})
it('never hands an advisor pledges outside the municipalities they administer', async () => {
const fixtures = campaignFixtures()
const advisor = await fixtures.createCampaignUser('advisor')
const administered = await fixtures.getMunicipality()
const foreign = await fixtures.getMunicipality()
await fixtures.assignMunicipalityAdvisors(administered, [advisor.id])
const contact = await fixtures.createContact()
const leadership = await fixtures.createLeadership({
contact: contact.id,
municipalities: [foreign.id],
supportStatus: 'engajado',
})
await fixtures.createVotePledge({
leadership: leadership.id,
municipality: foreign.id,
declaredVotes: 900,
})
// Empty `where`, but the advisor's scope is his portfolio — the whole-catalog
// shortcut must not apply, or this aggregate would carry a foreign pledge.
const scope = await loadMunicipalityScope(payload, advisor, {})
expect(scope.municipalities.map(({ id }) => id)).toEqual([administered.id])
expect(scope.pledgeAggregates.has(foreign.id)).toBe(false)
})
})