teqo-backup/tests/unit/dossieBulletin.unit.spec.ts
Francisco Solla 5644a9f947
Some checks are pending
Deploy / preflight (push) Waiting to run
Deploy / verify (push) Blocked by required conditions
Deploy / deploy staging (teqo-staging) (push) Blocked by required conditions
Deploy / requeue when main advanced (push) Blocked by required conditions
Deploy / deploy production (teqo-1313) (push) Blocked by required conditions
feat(C186/C187): dossiê corrente sem caps + redação, síntese e gráficos (paridade cidade × instituição)
Revisão de produto a partir do uso real (UFBA): as seções deixam de ser
capadas e fluem por quantas folhas precisarem, com packing medido
(probe → grow/shrink por folha, scripts/lib/dossiePack.mjs) e guarda de A4
no emit; o dossiê ganha redação de abertura (narrative.json escrito por
sub-agente e auditado pelo orquestrador), parágrafo de consolidação por
era, páginas de síntese e gráficos (recursos com fase, abrangência,
trajetória) e acervo como amostra declarada. O dono (dossieBlocks/
dossieRender/dossieUnit/buildPdf) foi generalizado e o ramo cidade adotou
as mesmas decisões; skills, comandos, agentes redatores, specs e designs
hi-fi re-sincronizados.
2026-09-17 23:00:08 -03:00

82 lines
3.3 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { BULLETIN_HIGHLIGHT_LIMIT, buildBulletin } from '../../scripts/lib/dossieBulletin.mjs'
import { MUNICIPALITY_UNIT } from '../../scripts/lib/dossieUnit.mjs'
const fact = (index: number, overrides: Record<string, unknown> = {}) => ({
id: `fato-${index}`,
era: 'C',
sphere: 'municipio',
area: 'Saúde',
headline: `Entrega ${index}`,
detail: `Detalhe ${index}`,
value: `R$ ${index} mil`,
year: '2024',
phase: 'empenhado',
sourceUrl: `https://exemplo.test/${index}`,
sourceDate: '2026-09-10',
...overrides,
})
const generatedAt = new Date('2026-09-17T12:00:00.000Z')
describe('buildBulletin', () => {
it('caps highlights and "e mais" items', () => {
const facts = Array.from({ length: 30 }, (_value, index) => fact(index))
const bulletin = buildBulletin({ facts, municipality: 'Ilhéus', generatedAt })
expect(bulletin.highlights).toHaveLength(BULLETIN_HIGHLIGHT_LIMIT)
// The unit descriptor owns the "E mais" budget (long labels wrap).
expect(bulletin.moreItems).toHaveLength(MUNICIPALITY_UNIT.bulletinMoreLimit)
})
it('counts the facts left out of the one-page boletim (never a silent drop, C188)', () => {
const facts = Array.from({ length: 25 }, (_value, index) => fact(index))
const bulletin = buildBulletin({ facts, municipality: 'Ilhéus', generatedAt })
expect(bulletin.factsTotal).toBe(25)
expect(bulletin.highlights.length + bulletin.moreItems.length + bulletin.factsRemaining).toBe(
bulletin.factsTotal,
)
})
it('has no remainder when everything fits', () => {
const bulletin = buildBulletin({ facts: [fact(1)], municipality: 'Ilhéus', generatedAt })
expect(bulletin.factsRemaining).toBe(0)
})
it('orders município before região and a sourced number before none', () => {
const facts = [
fact(1, { sphere: 'regiao' }),
fact(2, { value: null }),
fact(3, { sphere: 'municipio', value: '10 UPAs' }),
]
const bulletin = buildBulletin({ facts, municipality: 'Ilhéus', generatedAt })
expect(bulletin.highlights[0].title).toBe('Entrega 3')
})
it('composes the card eyebrow with area and sphere', () => {
const bulletin = buildBulletin({
facts: [fact(1, { sphere: 'regiao' })],
municipality: 'Ilhéus',
generatedAt,
})
expect(bulletin.highlights[0].eyebrow).toBe('Saúde · região')
})
it('renders an empty state without inventing facts', () => {
const bulletin = buildBulletin({ facts: [], municipality: 'Ilhéus', generatedAt })
expect(bulletin.highlights).toEqual([])
expect(bulletin.moreItems).toEqual([])
expect(bulletin.timeline.length).toBe(4)
})
it('maps every highlight and "e mais" item to a ledger fact (never invents)', () => {
const facts = Array.from({ length: 25 }, (_value, index) => fact(index))
const bulletin = buildBulletin({ facts, municipality: 'Ilhéus', generatedAt })
const headlines = new Set(facts.map((row) => row.headline))
expect(bulletin.highlights.length + bulletin.moreItems.length).toBe(
BULLETIN_HIGHLIGHT_LIMIT + MUNICIPALITY_UNIT.bulletinMoreLimit,
)
expect(bulletin.highlights.every((row) => headlines.has(row.title))).toBe(true)
expect(bulletin.moreItems.every((row) => headlines.has(row.label))).toBe(true)
})
})