teqo/tests/int/campaignUpdatesFeedData.int.spec.ts
2026-08-08 23:11:05 -03:00

164 lines
6.3 KiB
TypeScript

// @vitest-environment node
import { getPayload, type Payload } from 'payload'
import { beforeAll, describe, expect, it } from 'vitest'
import { municipalityCatalog } from '@/lib/municipalityCatalog'
import config from '@/payload.config'
import {
loadCampaignUpdatesFeed,
loadCampaignUpdatesFeedFacets,
} from '@/utilities/municipality/campaignUpdatesFeedData'
import { installCampaignFixtures } from '../helpers/campaignFixtures'
let payload: Payload
const campaignFixtures = installCampaignFixtures({
getPayload: () => payload,
setPayload: (nextPayload) => {
payload = nextPayload
},
})
describe('campaign updates feed data (C89)', () => {
beforeAll(async () => {
payload = await getPayload({ config: await config })
})
it('feeds the actor across their whole portfolio with author and municipality identity', async () => {
const coordinator = await campaignFixtures().createCampaignUser('coordinator')
const first = await campaignFixtures().getMunicipality()
const second = await campaignFixtures().getMunicipality()
await campaignFixtures().createMunicipalityUpdate({
municipality: first.id,
author: coordinator.id,
polarity: 'boa',
body: 'Festa da adesão',
})
await campaignFixtures().createMunicipalityUpdate({
municipality: second.id,
author: coordinator.id,
polarity: 'ruim',
urgent: true,
body: 'Perda de apoio',
})
// Scoped to this spec's municipalities: the coordinator's unrestricted
// read sees every update in the shared test DB, including rows other
// concurrently running spec files create — so global count assertions
// would race with them.
const result = await loadCampaignUpdatesFeed(payload, coordinator, {
page: 1,
slugs: [first.slug, second.slug],
})
expect(result.totalDocs).toBe(2)
expect(result.cards.some((card) => card.body === 'Festa da adesão')).toBe(true)
const urgentCard = result.cards.find((card) => card.body === 'Perda de apoio')
expect(urgentCard).toMatchObject({
polarity: 'ruim',
urgent: true,
author: { name: coordinator.name },
})
expect([first.slug, second.slug].includes(urgentCard!.municipality.slug)).toBe(true)
expect(urgentCard!.municipality.name.length).toBeGreaterThan(0)
})
it('scopes the feed and its facets to the advisor portfolio', async () => {
const coordinator = await campaignFixtures().createCampaignUser('coordinator')
const advisor = await campaignFixtures().createCampaignUser('advisor')
const otherAdvisor = await campaignFixtures().createCampaignUser('advisor')
const assigned = await campaignFixtures().getMunicipality()
const other = await campaignFixtures().getMunicipality()
await campaignFixtures().assignMunicipalityAdvisors(assigned, [advisor])
await campaignFixtures().assignMunicipalityAdvisors(other, [otherAdvisor])
await campaignFixtures().createMunicipalityUpdate({
municipality: assigned.id,
author: coordinator.id,
polarity: 'neutra',
body: 'Visita no meu município',
})
await campaignFixtures().createMunicipalityUpdate({
municipality: other.id,
author: otherAdvisor.id,
polarity: 'neutra',
body: 'Atualização alheia',
})
const result = await loadCampaignUpdatesFeed(payload, advisor, { page: 1 })
expect(result.totalDocs).toBe(1)
expect(result.cards[0]?.body).toBe('Visita no meu município')
const facets = await loadCampaignUpdatesFeedFacets(payload, advisor)
expect(facets.municipalities.map((municipality) => municipality.slug)).toEqual([assigned.slug])
expect(facets.authorOptions.map((option) => option.label)).toContain(coordinator.name)
expect(facets.authorOptions.map((option) => option.label)).not.toContain(otherAdvisor.name)
})
it('gives the coordinator the full municipality catalog as facet options', async () => {
const coordinator = await campaignFixtures().createCampaignUser('coordinator')
const facets = await loadCampaignUpdatesFeedFacets(payload, coordinator)
expect(facets.municipalities.map((municipality) => municipality.slug)).toEqual(
municipalityCatalog
.map((entry) => entry.slug)
.sort((left, right) => left.localeCompare(right, 'pt-BR')),
)
})
it('applies every feed filter to the query', async () => {
const coordinator = await campaignFixtures().createCampaignUser('coordinator')
const otherAuthor = await campaignFixtures().createCampaignUser('coordinator')
const municipality = await campaignFixtures().getMunicipality()
await campaignFixtures().createMunicipalityUpdate({
municipality: municipality.id,
author: coordinator.id,
polarity: 'boa',
urgent: true,
body: 'Adesão da comunidade',
})
await campaignFixtures().createMunicipalityUpdate({
municipality: municipality.id,
author: otherAuthor.id,
polarity: 'neutra',
body: 'Reunião de rotina',
})
// Every query below is scoped to this spec's municipality so counts can't
// race with concurrent spec files writing coordinator-visible updates.
const byText = await loadCampaignUpdatesFeed(payload, coordinator, {
page: 1,
slugs: [municipality.slug],
q: 'adesão',
})
expect(byText.cards.map((card) => card.body)).toEqual(['Adesão da comunidade'])
const byUrgent = await loadCampaignUpdatesFeed(payload, coordinator, {
page: 1,
slugs: [municipality.slug],
urgent: true,
})
expect(byUrgent.totalDocs).toBe(1)
const byAuthor = await loadCampaignUpdatesFeed(payload, coordinator, {
page: 1,
slugs: [municipality.slug],
authors: [otherAuthor.id],
})
expect(byAuthor.cards.map((card) => card.body)).toEqual(['Reunião de rotina'])
const byMunicipality = await loadCampaignUpdatesFeed(payload, coordinator, {
page: 1,
slugs: [municipality.slug],
})
expect(byMunicipality.totalDocs).toBe(2)
expect(byMunicipality.cards[0]?.municipality.slug).toBe(municipality.slug)
})
it('denies leaders the feed and its facets', async () => {
const leader = await campaignFixtures().createCampaignUser('leader')
await expect(loadCampaignUpdatesFeed(payload, leader, { page: 1 })).rejects.toThrow()
await expect(loadCampaignUpdatesFeedFacets(payload, leader)).rejects.toThrow()
})
})