// @vitest-environment node import type { Payload } from 'payload' import { getPayload } from 'payload' import { beforeAll, describe, expect, it } from 'vitest' import { getMunicipalityFederalBaseline, getStatewideFederalTotals, } from '@/lib/bahiaElectionAggregates' import { getMunicipalityCatalogEntry, municipalityCatalog } from '@/lib/municipalityCatalog' import { DEFAULT_VOTE_RANK_YEAR } from '@/lib/municipalityVoteRank' import { territorialClassSortWeight } from '@/lib/territorialClassSortWeight' import config from '@/payload.config' import { loadMunicipalityListPageBundle } from '@/utilities/municipality/municipalityPageData' import { computeMunicipalityTerritorialClass } from '@/utilities/municipality/municipalityTerritorialClass' import { cityFederalBaseline } from '@/utilities/municipality/salvadorCityAggregates' import { installCampaignFixtures } from '../helpers/campaignFixtures' let payload: Payload const campaignFixtures = installCampaignFixtures({ getPayload: () => payload, setPayload: (nextPayload) => { payload = nextPayload }, }) describe('loadMunicipalityListPageBundle', () => { beforeAll(async () => { payload = await getPayload({ config: await config }) }) it('returns an empty list when the filtered municipality set is empty', async () => { const coordinator = await campaignFixtures().createCampaignUser('coordinator') const bundle = await loadMunicipalityListPageBundle(payload, coordinator, { q: 'zzznomatch' }) expect(bundle.municipalities).toHaveLength(0) expect(bundle.totalDocs).toBe(0) expect(bundle.sliceTotals).toBeNull() }) it('includes 2022 vote position on list rows', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const municipality = await fixtures.getMunicipality() fixtures.touchMunicipality(municipality.id) const bundle = await loadMunicipalityListPageBundle(payload, coordinator, { q: municipality.name, }) const row = bundle.municipalities.find((item) => item.slug === municipality.slug) expect(row?.votePosition2022).not.toBeNull() expect(row!.votePosition2022!.totalUnits).toBe(435) expect(row!.votePosition2022!.rank).toBeGreaterThanOrEqual(1) }) it('orders the filtered set by 2022 votes when sort=votos', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const first = await fixtures.getMunicipality() const second = await fixtures.getMunicipality() fixtures.touchMunicipality(first.id) fixtures.touchMunicipality(second.id) const marker = `a11-votos-${Date.now()}` await payload.update({ collection: 'municipality', id: first.id, data: { name: `${marker}-alpha` }, depth: 0, overrideAccess: true, }) await payload.update({ collection: 'municipality', id: second.id, data: { name: `${marker}-beta` }, depth: 0, overrideAccess: true, }) const bundle = await loadMunicipalityListPageBundle(payload, coordinator, { q: marker, sort: 'votos', }) expect(bundle.municipalities.length).toBeGreaterThanOrEqual(2) const votes = bundle.municipalities.map((row) => row.votePosition2022?.votes ?? 0) const nonZero = votes.filter((value) => value > 0) for (let index = 1; index < nonZero.length; index += 1) { expect(nonZero[index - 1]!).toBeGreaterThanOrEqual(nonZero[index]!) } // Zeros (if any) must trail the non-zero block. const firstZero = votes.findIndex((value) => value === 0) if (firstZero >= 0) { expect(votes.slice(firstZero).every((value) => value === 0)).toBe(true) } }) /** * E9 allocation queue: the default ordering. Uses `expectedVotes` (mesa * goals) so the deficits are pinned by the fixture instead of by whatever * the 2022 artifact says for the allocated slugs. */ it('orders by uncovered deficit (default sort), biggest gap first', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const wideGap = await fixtures.getMunicipality() const nearlyCovered = await fixtures.getMunicipality() const marker = `e9-deficit-${Date.now()}` await payload.update({ collection: 'municipality', id: wideGap.id, data: { name: `${marker}-wide`, expectedVotes: { pessimistic: null, central: 5_000, optimistic: null }, }, depth: 0, overrideAccess: true, }) fixtures.touchMunicipality(wideGap.id) await payload.update({ collection: 'municipality', id: nearlyCovered.id, data: { name: `${marker}-near`, expectedVotes: { pessimistic: null, central: 1_000, optimistic: null }, }, depth: 0, overrideAccess: true, }) fixtures.touchMunicipality(nearlyCovered.id) const contact = await fixtures.createContact() const leadership = await fixtures.createLeadership({ contact: contact.id, municipalities: [nearlyCovered.id], supportStatus: 'engajado', }) await fixtures.createVotePledge({ leadership: leadership.id, municipality: nearlyCovered.id, declaredVotes: 900, estimatedVotes: { pessimistic: null, central: 900, optimistic: null }, }) const descending = await loadMunicipalityListPageBundle(payload, coordinator, { q: marker }) expect(descending.municipalities.map((row) => row.slug)).toEqual([ wideGap.slug, nearlyCovered.slug, ]) expect(descending.municipalities[0]!.goalCoverageByScenario.central.deficit).toBe(5_000) expect(descending.municipalities[1]!.goalCoverageByScenario.central.deficit).toBe(100) const ascending = await loadMunicipalityListPageBundle(payload, coordinator, { q: marker, sort: 'deficit', dir: 'asc', }) expect(ascending.municipalities.map((row) => row.slug)).toEqual([ nearlyCovered.slug, wideGap.slug, ]) }) it('orders by frescor with "never had a signal" ahead of the oldest signal', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const silent = await fixtures.getMunicipality() const touched = await fixtures.getMunicipality() const marker = `e9-frescor-${Date.now()}` await payload.update({ collection: 'municipality', id: silent.id, data: { name: `${marker}-silent`, lastUpdateAt: null }, depth: 0, overrideAccess: true, }) fixtures.touchMunicipality(silent.id) await payload.update({ collection: 'municipality', id: touched.id, data: { name: `${marker}-touched` }, depth: 0, overrideAccess: true, }) // The collection hook recomputes `lastUpdateAt` from this update. await fixtures.createMunicipalityUpdate({ municipality: touched.id, author: coordinator.id, }) const coldestFirst = await loadMunicipalityListPageBundle(payload, coordinator, { q: marker, sort: 'frescor', }) expect(coldestFirst.municipalities.map((row) => row.slug)).toEqual([silent.slug, touched.slug]) expect(coldestFirst.municipalities[0]!.lastSignalAt).toBeNull() expect(coldestFirst.municipalities[1]!.lastSignalAt).not.toBeNull() const freshestFirst = await loadMunicipalityListPageBundle(payload, coordinator, { q: marker, sort: 'frescor', dir: 'asc', }) expect(freshestFirst.municipalities.map((row) => row.slug)).toEqual([touched.slug, silent.slug]) }) it('counts a pledge date as a signal even when no staff update exists', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const municipality = await fixtures.getMunicipality() fixtures.touchMunicipality(municipality.id) const marker = `e9-pledge-signal-${Date.now()}` await payload.update({ collection: 'municipality', id: municipality.id, data: { name: marker, lastUpdateAt: null }, depth: 0, overrideAccess: true, }) const contact = await fixtures.createContact() const leadership = await fixtures.createLeadership({ contact: contact.id, municipalities: [municipality.id], supportStatus: 'engajado', }) // `declaredAt` is stamped by the collection's own beforeChange hook, so the // fixture cannot pin it — read it back and assert the signal matches. const pledge = await fixtures.createVotePledge({ leadership: leadership.id, municipality: municipality.id, declaredVotes: 50, }) expect(pledge.declaredAt).toBeTruthy() const bundle = await loadMunicipalityListPageBundle(payload, coordinator, { q: marker }) const row = bundle.municipalities.find((item) => item.slug === municipality.slug) expect(row?.lastUpdateAt).toBeNull() expect(row?.lastSignalAt).toBe(pledge.declaredAt) expect(row?.pledges.lastPledgeAt).toBe(pledge.declaredAt) }) /** * E10: the class is derived from the committed TSE artifact, so the filter * cannot be a Payload constraint. The bundle must still agree with itself — * rows and `totalDocs` counting the filtered scope. */ it('filters by the derived territorial class and keeps totals honest', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') // Two allocated municipalities with DISTINCT territorial classes: the // behavior pinned here (class filter narrows, totals stay honest, classe // sort follows the weight table) does not care WHICH classes they are — // and pinning fixed catalog slugs raced parallel specs mutating the same // seeded rows (deadlock on municipality_rels, miss #73). const first = await fixtures.getMunicipality() const firstClass = computeMunicipalityTerritorialClass(first.slug).class let second = await fixtures.getMunicipality() let secondClass = computeMunicipalityTerritorialClass(second.slug).class for (let attempt = 0; secondClass === firstClass && attempt < 20; attempt++) { second = await fixtures.getMunicipality() secondClass = computeMunicipalityTerritorialClass(second.slug).class } if (secondClass === firstClass) { throw new Error('could not allocate municipalities of two distinct classes') } const marker = `e10-classe-${Date.now()}` for (const [municipality, suffix] of [ [first, 'filtrada'], [second, 'fora'], ] as const) { await payload.update({ collection: 'municipality', id: municipality.id, data: { name: `${marker}-${suffix}` }, depth: 0, overrideAccess: true, }) fixtures.touchMunicipality(municipality.id) } const filtered = await loadMunicipalityListPageBundle(payload, coordinator, { q: marker, class: firstClass, }) expect(filtered.municipalities.map((row) => row.slug)).toEqual([first.slug]) expect(filtered.totalDocs).toBe(1) expect(filtered.municipalities[0]!.territorialClass).toBe(firstClass) expect(filtered.municipalities[0]!.territorialClassFactors.length).toBeGreaterThan(0) // A native sort key would otherwise let Payload paginate before the class // filter runs, which would hand back a short page with an inflated total. const byName = await loadMunicipalityListPageBundle(payload, coordinator, { q: marker, class: firstClass, sort: 'name', }) expect(byName.municipalities.map((row) => row.slug)).toEqual([first.slug]) expect(byName.totalDocs).toBe(1) const sorted = await loadMunicipalityListPageBundle(payload, coordinator, { q: marker, sort: 'classe', }) // `classe` sorts strongest class first (reduto 4 … marginal 1; every // catalog row classes into a weighted class, so no null weight exists). const expectedOrder = [first, second] .map((municipality) => ({ slug: municipality.slug, weight: territorialClassSortWeight[computeMunicipalityTerritorialClass(municipality.slug).class], })) .sort((left, right) => (right.weight ?? 0) - (left.weight ?? 0)) .map((entry) => entry.slug) expect(sorted.municipalities.map((row) => row.slug)).toEqual(expectedOrder) }) /** * E14: `nivel` is a stored column, so ordering is Postgres's. With no * backfill almost every município is null, and where the nulls land decides * what page 1 of "N4 primeiro" actually shows — so it is pinned rather than * inferred from the label. */ it('sorts by nível with the un-levelled municípios last in both directions', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const low = await fixtures.getMunicipality() const high = await fixtures.getMunicipality() const none = await fixtures.getMunicipality() const marker = `e14-nivel-${Date.now()}` for (const [municipality, suffix, engagementLevel] of [ [low, 'n0', 'n0'], [high, 'n4', 'n4'], [none, 'sem', null], ] as const) { await payload.update({ collection: 'municipality', id: municipality.id, data: { name: `${marker}-${suffix}`, engagementLevel }, depth: 0, overrideAccess: true, }) fixtures.touchMunicipality(municipality.id) } const descending = await loadMunicipalityListPageBundle(payload, coordinator, { q: marker, sort: 'nivel', dir: 'desc', }) expect(descending.municipalities.map((row) => row.engagementLevel)).toEqual(['n4', 'n0', null]) const ascending = await loadMunicipalityListPageBundle(payload, coordinator, { q: marker, sort: 'nivel', dir: 'asc', }) expect(ascending.municipalities.map((row) => row.engagementLevel)).toEqual(['n0', 'n4', null]) }) it('keeps advisor access and applies URL filters on top', async () => { const fixtures = campaignFixtures() const advisor = await fixtures.createCampaignUser('advisor') const administered = await fixtures.getMunicipality() await fixtures.assignMunicipalityAdvisors(administered.id, [advisor.id]) const included = await loadMunicipalityListPageBundle(payload, advisor, { q: administered.name, }) expect(included.municipalities.some((row) => row.slug === administered.slug)).toBe(true) const outsideSlug = municipalityCatalog.find((entry) => entry.slug !== administered.slug)!.slug const excluded = await loadMunicipalityListPageBundle(payload, advisor, { slug: [outsideSlug], }) expect(excluded.municipalities).toHaveLength(0) }) it('cross-filters column-filter options but never narrows a filter by itself', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const municipality = await fixtures.getMunicipality() const catalogEntry = getMunicipalityCatalogEntry(municipality.slug) expect(catalogEntry).toBeDefined() const outsideRegion = municipalityCatalog.find( (entry) => entry.region !== catalogEntry!.region, )! const bundle = await loadMunicipalityListPageBundle(payload, coordinator, { region: catalogEntry!.region, }) // The território filter narrows the Município options… expect(bundle.filterFacets.slugs).toContain(municipality.slug) expect(bundle.filterFacets.slugs).not.toContain(outsideRegion.slug) expect(bundle.filterFacets.slugs.length).toBeLessThan(municipalityCatalog.length) // …but not its own: the OR set must stay addable. expect(bundle.filterFacets.regions.length).toBeGreaterThan(1) // A selected value stays listed even when other filters exclude it, so it // can be undone from the popover. const conflicting = await loadMunicipalityListPageBundle(payload, coordinator, { region: catalogEntry!.region, slug: outsideRegion.slug, }) expect(conflicting.municipalities).toHaveLength(0) expect(conflicting.filterFacets.slugs).toContain(outsideRegion.slug) }) it('keeps the options of filters that share a popover with the applied one', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const advisor = await fixtures.createCampaignUser('advisor') const priorityMunicipality = await fixtures.getMunicipality() await payload.update({ collection: 'municipality', id: priorityMunicipality.id, data: { priority: 'alta' }, overrideAccess: true, }) const covered = await fixtures.getMunicipality() await fixtures.assignMunicipalityAdvisors(covered.id, [advisor.id]) // "Prioritária" lives in the Município popover, so it must not hide the // municipalities that popover is there to offer. const byPriority = await loadMunicipalityListPageBundle(payload, coordinator, { priority: 'alta', }) expect(byPriority.municipalities.every((row) => row.priority === 'alta')).toBe(true) expect(byPriority.filterFacets.slugs).toContain(covered.slug) // Same for the "Sem assessor" toggle inside the Assessores popover: it would // otherwise leave that popover with nobody to pick. const withoutAdvisor = await loadMunicipalityListPageBundle(payload, coordinator, { coverage: 'sem_assessor', }) expect(withoutAdvisor.filterFacets.advisorIDs).toContain(advisor.id) }) it('returns an empty bundle for leaders (municipality list lockdown)', async () => { const fixtures = campaignFixtures() const municipality = await fixtures.getMunicipality() const leader = await fixtures.createCampaignUser('leader') const contact = await fixtures.createContact() await fixtures.createLeadership({ contact: contact.id, municipalities: [municipality.id], user: leader.id, supportStatus: 'engajado', }) const bundle = await loadMunicipalityListPageBundle(payload, leader, { q: municipality.name }) expect(bundle.municipalities).toHaveLength(0) expect(bundle.scopeTotal).toBe(0) expect(bundle.sliceTotals).toBeNull() }) // ------------------------------------------------------------------------- // B178 — Salvador city aggregate row (virtual, common-row behavior) // ------------------------------------------------------------------------- const salvadorZoneSlugs = municipalityCatalog .filter((entry) => entry.kind === 'zona' && entry.city === 'Salvador') .map((entry) => entry.slug) const cityRow = (bundle: Awaited>) => bundle.municipalities.find((row) => row.slug === 'salvador') it('shows the city row alongside the 19 zones when q matches Salvador', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const bundle = await loadMunicipalityListPageBundle(payload, coordinator, { q: 'salvador' }) expect(bundle.municipalities).toHaveLength(20) expect(bundle.totalDocs).toBe(20) for (const slug of salvadorZoneSlugs) { expect(bundle.municipalities.some((row) => row.slug === slug)).toBe(true) } const city = cityRow(bundle) expect(city).toBeDefined() expect(city?.isCity).toBe(true) expect(city?.id).toBeLessThan(0) }) it('includes the city row in the default recorte with honest totals (436 rows)', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const bundle = await loadMunicipalityListPageBundle(payload, coordinator, {}) // The city counts as a row (it is a common line of the list) but never // as an operational unit: the catalog stays at 435. expect(bundle.totalDocs).toBe(municipalityCatalog.length + 1) expect(bundle.totalPages).toBe(Math.ceil(bundle.totalDocs / 25)) expect(bundle.municipalities).toHaveLength(25) }) it('renders the city row with the competitive position and a real aggregate class', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const bundle = await loadMunicipalityListPageBundle(payload, coordinator, { q: 'salvador' }) const city = cityRow(bundle) expect(city?.votePosition2022).not.toBeNull() expect(city?.votePosition2022?.votes).toBeGreaterThan(0) expect(city?.votePosition2022?.rank).toBeGreaterThanOrEqual(1) expect(city?.votePosition2022?.totalUnits).toBeGreaterThanOrEqual(city!.votePosition2022!.rank) // The aggregate class of the capital comes from the summed artifact, never // from a per-slug lookup that would read "Sem base" for the unknown slug. expect(city?.territorialClass).not.toBe('sem_base') }) it('selects the city row by its own slug filter', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const bundle = await loadMunicipalityListPageBundle(payload, coordinator, { slug: ['salvador'], }) expect(bundle.municipalities).toHaveLength(1) expect(cityRow(bundle)?.isCity).toBe(true) expect(bundle.totalDocs).toBe(1) }) it('selects the city row under the Metropolitano region filter but not others', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const metropolitano = await loadMunicipalityListPageBundle(payload, coordinator, { q: 'salvador', region: ['Metropolitano de Salvador'], }) expect(cityRow(metropolitano)).toBeDefined() expect(metropolitano.totalDocs).toBe(20) const chapada = await loadMunicipalityListPageBundle(payload, coordinator, { q: 'salvador', region: ['Chapada Diamantina'], }) expect(cityRow(chapada)).toBeUndefined() expect(chapada.municipalities).toHaveLength(0) }) it('selects the city row under absence sentinels and excludes it under named values', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const semNivel = await loadMunicipalityListPageBundle(payload, coordinator, { q: 'salvador', level: ['sem_nivel'], }) expect(cityRow(semNivel)).toBeDefined() expect(semNivel.totalDocs).toBe(20) const nivelN0 = await loadMunicipalityListPageBundle(payload, coordinator, { q: 'salvador', level: ['n0'], }) expect(cityRow(nivelN0)).toBeUndefined() expect(nivelN0.municipalities).toHaveLength(0) const comAssessor = await loadMunicipalityListPageBundle(payload, coordinator, { q: 'salvador', coverage: 'com_assessor', }) expect(cityRow(comAssessor)).toBeUndefined() }) it('positions the city row under a native sort without re-sorting the rest', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const bundle = await loadMunicipalityListPageBundle(payload, coordinator, { q: 'salvador', sort: 'name', }) // The DB rows keep the SQL order verbatim — the city is INSERTED, never // re-sorted with the rest (a full in-memory sort would drift collation). const direct = await payload.find({ collection: 'municipality', where: { name: { contains: 'salvador' } }, depth: 0, limit: 0, pagination: false, sort: 'name', select: { slug: true }, overrideAccess: true, }) const directOrder = direct.docs.map((doc) => doc.slug) const bundleZoneOrder = bundle.municipalities .filter((row) => row.slug !== 'salvador') .map((row) => row.slug) expect(bundleZoneOrder).toEqual(directOrder) // The city lands inside the Salvador block — under pt-BR collation the // "— ZE N" names sort before "Salvador (cidade)", so it sits at the block // edge (immediately after the last zone), never at the recorte start. const cityIndex = bundle.municipalities.findIndex((row) => row.slug === 'salvador') expect(cityIndex).toBeGreaterThan(0) expect(bundle.municipalities[cityIndex - 1]?.kind).toBe('zona') }) it('orders the city row by its real summed votes under sort=votos', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const descending = await loadMunicipalityListPageBundle(payload, coordinator, { q: 'salvador', sort: 'votos', }) expect(descending.municipalities[0]?.slug).toBe('salvador') expect(descending.municipalities[0]?.isCity).toBe(true) const ascending = await loadMunicipalityListPageBundle(payload, coordinator, { q: 'salvador', sort: 'votos', dir: 'asc', }) expect(ascending.municipalities[ascending.municipalities.length - 1]?.slug).toBe('salvador') }) it('paginates the city row like a common row (last page) and beyond totalPages', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') // Metropolitano de Salvador: catalog municipalities + the city row, sorted // by name — the Salvador block (with the city) lands on the last page. const metropolitanoCount = municipalityCatalog.filter((entry) => entry.region === 'Metropolitano de Salvador').length + 1 const pageOne = await loadMunicipalityListPageBundle(payload, coordinator, { region: ['Metropolitano de Salvador'], sort: 'name', }) expect(pageOne.totalDocs).toBe(metropolitanoCount) expect(pageOne.totalPages).toBe(Math.ceil(metropolitanoCount / 25)) expect(pageOne.municipalities).toHaveLength(25) expect(pageOne.municipalities.some((row) => row.slug === 'salvador')).toBe(false) const lastPage = pageOne.totalPages const pageLast = await loadMunicipalityListPageBundle(payload, coordinator, { region: ['Metropolitano de Salvador'], sort: 'name', page: String(lastPage), }) expect(pageLast.municipalities.some((row) => row.slug === 'salvador')).toBe(true) expect(pageLast.municipalities).toHaveLength(metropolitanoCount - 25 * (lastPage - 1)) const beyond = await loadMunicipalityListPageBundle(payload, coordinator, { region: ['Metropolitano de Salvador'], sort: 'name', page: String(lastPage + 1), }) expect(beyond.municipalities).toHaveLength(0) }) it('keeps the advisor rule conjunctive: city hidden without q, filtered by other filters', async () => { const fixtures = campaignFixtures() const advisor = await fixtures.createCampaignUser('advisor') const administered = await fixtures.getMunicipality() await fixtures.assignMunicipalityAdvisors(administered.id, [advisor.id]) // Slug recorte alone does not reveal the city to an advisor (only q does). const bySlug = await loadMunicipalityListPageBundle(payload, advisor, { slug: ['salvador'], }) expect(cityRow(bySlug)).toBeUndefined() // q + a filter the city passes keeps it; q + a named-value filter hides it. const withAbsence = await loadMunicipalityListPageBundle(payload, advisor, { q: 'salvador', coverage: 'sem_assessor', }) expect(cityRow(withAbsence)).toBeDefined() const withNamed = await loadMunicipalityListPageBundle(payload, advisor, { q: 'salvador', level: ['n0'], }) expect(cityRow(withNamed)).toBeUndefined() }) it('shows the city row to an advisor only when they search for the city', async () => { const fixtures = campaignFixtures() const advisor = await fixtures.createCampaignUser('advisor') const administered = await fixtures.getMunicipality() await fixtures.assignMunicipalityAdvisors(administered.id, [advisor.id]) const defaultList = await loadMunicipalityListPageBundle(payload, advisor, {}) expect(cityRow(defaultList)).toBeUndefined() const searched = await loadMunicipalityListPageBundle(payload, advisor, { q: 'salvador' }) expect(cityRow(searched)).toBeDefined() }) // ------------------------------------------------------------------------- // B202 — totals of the filtered slice (footer line) // ------------------------------------------------------------------------- const baselineVotes = (slug: string): number => getMunicipalityFederalBaseline(slug).votesByYear[String(DEFAULT_VOTE_RANK_YEAR)] ?? 0 it('sums the whole default recorte to the statewide 2022 votes', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const bundle = await loadMunicipalityListPageBundle(payload, coordinator, {}) expect(bundle.sliceTotals?.rowCount).toBe(bundle.totalDocs) expect(bundle.sliceTotals?.rowCount).toBe(municipalityCatalog.length + 1) expect(bundle.sliceTotals?.votes2022).toBe( getStatewideFederalTotals(DEFAULT_VOTE_RANK_YEAR).ownVotes, ) }) it('covers every page of a paged recorte: the visible page is not the total', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const region = 'Litoral Sul' const regionEntries = municipalityCatalog.filter((entry) => entry.region === region) const expectedVotes = regionEntries.reduce((sum, entry) => sum + baselineVotes(entry.slug), 0) const bundle = await loadMunicipalityListPageBundle(payload, coordinator, { region: [region], sort: 'name', }) expect(regionEntries.length).toBeGreaterThan(25) expect(bundle.municipalities).toHaveLength(25) expect(bundle.totalDocs).toBe(regionEntries.length) expect(bundle.sliceTotals?.rowCount).toBe(regionEntries.length) expect(bundle.sliceTotals?.votes2022).toBe(expectedVotes) }) it('sums expectations per scenario and counts the rows with any estimate', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const first = await fixtures.getMunicipality() const second = await fixtures.getMunicipality() const third = await fixtures.getMunicipality() await payload.update({ collection: 'municipality', id: first.id, data: { expectedVotes: { pessimistic: 100, central: 250, optimistic: 400 } }, depth: 0, overrideAccess: true, }) await payload.update({ collection: 'municipality', id: second.id, data: { expectedVotes: { pessimistic: 50, central: null, optimistic: null } }, depth: 0, overrideAccess: true, }) for (const municipality of [first, second, third]) { fixtures.touchMunicipality(municipality.id) } const bundle = await loadMunicipalityListPageBundle(payload, coordinator, { slug: [first.slug, second.slug, third.slug], }) expect(bundle.sliceTotals?.rowCount).toBe(3) expect(bundle.sliceTotals?.expectedByScenario).toEqual({ pessimistic: 150, central: 250, optimistic: 400, }) expect(bundle.sliceTotals?.withEstimateCount).toBe(2) }) it('counts Salvador once under q: 2022 equals the city fold, never city plus zones', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const bundle = await loadMunicipalityListPageBundle(payload, coordinator, { q: 'salvador' }) const cityVotes = cityFederalBaseline().votesByYear[String(DEFAULT_VOTE_RANK_YEAR)]! expect(cityVotes).toBeGreaterThan(0) expect(bundle.municipalities).toHaveLength(20) expect(bundle.sliceTotals?.rowCount).toBe(20) expect(bundle.sliceTotals?.votes2022).toBe(cityVotes) }) it('sums the city baseline when only the city row is selected', async () => { const fixtures = campaignFixtures() const coordinator = await fixtures.createCampaignUser('coordinator') const bundle = await loadMunicipalityListPageBundle(payload, coordinator, { slug: ['salvador'], }) expect(bundle.sliceTotals?.rowCount).toBe(1) expect(bundle.sliceTotals?.votes2022).toBe( cityFederalBaseline().votesByYear[String(DEFAULT_VOTE_RANK_YEAR)]!, ) }) it('scopes the totals to the advisor carteira', async () => { const fixtures = campaignFixtures() const advisor = await fixtures.createCampaignUser('advisor') const administered = await fixtures.getMunicipality() await fixtures.assignMunicipalityAdvisors(administered.id, [advisor.id]) const bundle = await loadMunicipalityListPageBundle(payload, advisor, {}) expect(bundle.sliceTotals?.rowCount).toBe(1) expect(bundle.sliceTotals?.votes2022).toBe(baselineVotes(administered.slug)) }) it('mirrors the row scope for an advisor with Visão Tudo', async () => { const fixtures = campaignFixtures() const advisor = await fixtures.createCampaignUser('advisor', { visibility: 'tudo', editing: 'tudo', }) const bundle = await loadMunicipalityListPageBundle(payload, advisor, {}) expect(bundle.municipalities.length).toBeLessThan(bundle.totalDocs) expect(bundle.sliceTotals?.rowCount).toBe(municipalityCatalog.length) expect(bundle.sliceTotals?.votes2022).toBe( getStatewideFederalTotals(DEFAULT_VOTE_RANK_YEAR).ownVotes, ) }) })