teqo/tests/unit/campaignEntityListParsers.unit.spec.ts
Francisco Ignácio Fontoura Solla 8c55daffb2 B33: ordenação e filtro no header da lista de dobradinhas
- stateDeputyListUrl.ts / stateDeputyListFilters.ts: contrato de URL/filtro
  próprio (sort/dir, filtro de Partido multi + sentinela "Sem partido"),
  espelhando municipalityListUrl.ts (paginação/resolveListUrl) e
  territoryListUrl.ts (sort keys/labels)
- stateDeputyData.ts: where/sort resolvidos no banco + facet de partido
  (loadStateDeputyPartyFacet), select estreito na query principal
- StateDeputySortableHead / StateDeputyHeaderFilter / StateDeputyFilters:
  wrappers finos sobre o chrome compartilhado (shared/CampaignSortableHead,
  CampaignHeaderFilterPopover), paridade mobile incluída
- dobradinhas/page.tsx: redirect canônico em duas fases, CampaignTable
  sempre montada com caption + empty state, resumo de ordenação aria-live
- Correção pós-entrega (design review): "Sem partido" no mobile + caption
  da tabela + copy plural do empty state
- /simplify (1ª rodada): buildStateDeputyPartyOptions compartilhado, remove
  discriminante filterParam redundante, dedupe/if mortos em
  stateDeputyListUrl.ts
- /simplify (2ª rodada, pós-rebase): remove cast/type morto em
  stateDeputyData.ts, stateDeputyColumns usa StateDeputyFilterOption em vez
  de duplicar a forma, inlinea parsePartiesParam; extrai truncatedNamesLabel
  compartilhado em campaignListUrl.ts (3º call site — municipalityListFilters
  e territoryListFilters tinham a mesma função com nomes distintos)

Gate verde (tsc, lint, format, check:cycles, 396 testes, build); Aikido
0 achados nos 7 arquivos tocados nesta rodada. Docs:
docs/plans/ordenacao-filtros-lista-dobradinhas.md, docs/roadmap.md,
.cursor/rules/projects/nucleos-eleitorais.mdc.
2026-07-26 16:21:40 -03:00

76 lines
2.9 KiB
TypeScript

/**
* Pins the "simple" entity list parsers ahead of the Pass 2 list-system
* consolidation (W1): lideranças, organizações, demandas and assessores.
* Their URL contracts must survive the migration byte-identical. Dobradinhas
* left this group in B33 — its parser grew a full sort/filter contract of its
* own and moved to `stateDeputyListUrl.ts`, pinned in
* `stateDeputyListUrl.unit.spec.ts`.
*/
import { describe, expect, it } from 'vitest'
import { advisorListHrefForPage, parseAdvisorListParams } from '@/utilities/advisorData'
import { parseDemandListParams } from '@/utilities/campaignDemandData'
import { parseLeadershipListParams } from '@/utilities/leadershipData'
import { parseOrganizationListParams } from '@/utilities/organizationData'
const qAndPageParsers = [
['leadership', parseLeadershipListParams],
['advisor', parseAdvisorListParams],
] as const
describe.each(qAndPageParsers)('%s list parser (q + page)', (_name, parse) => {
it('defaults to page 1 without q', () => {
expect(parse({})).toEqual({ page: 1 })
})
it('validates page as a positive decimal integer', () => {
expect(parse({ page: '4' }).page).toBe(4)
expect(parse({ page: '0' }).page).toBe(1)
expect(parse({ page: '-2' }).page).toBe(1)
expect(parse({ page: '01' }).page).toBe(1)
expect(parse({ page: 'abc' }).page).toBe(1)
})
it('trims q, omits it when empty and takes the first repeated cell', () => {
expect(parse({ q: ' ana ' }).q).toBe('ana')
expect(parse({ q: ' ' }).q).toBeUndefined()
expect(parse({ q: ['primeiro', 'segundo'] }).q).toBe('primeiro')
})
})
describe('parseOrganizationListParams', () => {
it('keeps only known organization kinds', () => {
expect(parseOrganizationListParams({ kind: 'sindicato' }).kind).toBe('sindicato')
expect(parseOrganizationListParams({ kind: 'clube' }).kind).toBeUndefined()
})
it('combines q, kind and page', () => {
expect(parseOrganizationListParams({ q: 'cut', kind: 'sindicato', page: '2' })).toEqual({
page: 2,
q: 'cut',
kind: 'sindicato',
})
})
})
describe('parseDemandListParams', () => {
it('keeps only known statuses and kinds', () => {
expect(parseDemandListParams({ status: 'aberta' }).status).toBe('aberta')
expect(parseDemandListParams({ status: 'fechada' }).status).toBeUndefined()
expect(parseDemandListParams({ kind: 'material' }).kind).toBe('material')
expect(parseDemandListParams({ kind: 'outra-coisa' }).kind).toBeUndefined()
})
it('defaults to page 1 with no filters', () => {
expect(parseDemandListParams({})).toEqual({ page: 1 })
})
})
describe('advisorListHrefForPage', () => {
it('serializes q then page against the assessores base path', () => {
expect(advisorListHrefForPage({ page: 1 }, 1)).toBe('/campanha/assessores')
expect(advisorListHrefForPage({ page: 1, q: 'edi' }, 3)).toBe(
'/campanha/assessores?q=edi&page=3',
)
})
})