teqo-backup/tests/unit/supporterUi.unit.spec.ts
Cursor Agent b509c7d7b3
B141 — filtro por fonte na omnibox de apoiadores (#309)
Adiciona dimensão Fonte ao estado de lista, where-builder, aggregate SQL
e adapter omnibox (B128), com guard isSupporterSource e testes.

Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
2026-08-02 23:03:22 +00:00

122 lines
4.5 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
buildSupporterFiltersKey,
buildSupporterListHref,
buildSupporterListSearchParams,
canAccessSupporterArea,
getSupporterScopeLabel,
parseSupporterListParams,
resolveSupporterListUrl,
} from '@/utilities/supporter/supporterUi'
describe('parseSupporterListParams', () => {
it('defaults to page 1 with no filters', () => {
expect(parseSupporterListParams({})).toEqual({ page: 1 })
})
it('validates page strictly (positive decimal integer)', () => {
expect(parseSupporterListParams({ page: '3' }).page).toBe(3)
expect(parseSupporterListParams({ page: '0' }).page).toBe(1)
expect(parseSupporterListParams({ page: '02' }).page).toBe(1)
expect(parseSupporterListParams({ page: 'x' }).page).toBe(1)
})
it('trims q and omits it when empty', () => {
expect(parseSupporterListParams({ q: ' maria ' }).q).toBe('maria')
expect(parseSupporterListParams({ q: ' ' }).q).toBeUndefined()
})
it('keeps only known vote intentions', () => {
expect(parseSupporterListParams({ voteIntention: 'certo' }).voteIntention).toBe('certo')
expect(parseSupporterListParams({ voteIntention: 'talvez' }).voteIntention).toBeUndefined()
})
it('keeps only known sources', () => {
expect(parseSupporterListParams({ source: 'import_csv' }).source).toBe('import_csv')
expect(parseSupporterListParams({ source: 'lideranca' }).source).toBe('lideranca')
expect(parseSupporterListParams({ source: 'spam' }).source).toBeUndefined()
})
it('canonicalizes city through the Bahia municipality resolver', () => {
expect(parseSupporterListParams({ city: ' salvador ' }).city).toBe('Salvador')
expect(parseSupporterListParams({ city: 'Gotham' }).city).toBeUndefined()
})
it('parses municipality as a strict positive integer', () => {
expect(parseSupporterListParams({ municipality: '42' }).municipality).toBe(42)
expect(parseSupporterListParams({ municipality: '-1' }).municipality).toBeUndefined()
})
it('takes the first cell of repeated params', () => {
expect(parseSupporterListParams({ q: ['ana', 'bia'] }).q).toBe('ana')
})
})
describe('buildSupporterListSearchParams', () => {
it('serializes in canonical order and omits page 1', () => {
const params = buildSupporterListSearchParams({
page: 1,
q: 'ana',
voteIntention: 'certo',
source: 'import_csv',
city: 'Salvador',
municipality: 7,
})
expect(params.toString()).toBe(
'q=ana&voteIntention=certo&source=import_csv&city=Salvador&municipality=7',
)
})
it('includes page only beyond 1 and supports the page override', () => {
expect(buildSupporterListSearchParams({ page: 2 }).toString()).toBe('page=2')
expect(buildSupporterListSearchParams({ page: 1 }, 5).toString()).toBe('page=5')
})
})
describe('buildSupporterFiltersKey / buildSupporterListHref', () => {
it('derives a stable filters key from the canonical serialization', () => {
expect(buildSupporterFiltersKey({ page: 3, q: 'ana' })).toBe('q=ana&page=3')
})
it('builds hrefs against the supporters base path', () => {
expect(buildSupporterListHref({ page: 1 }, 1)).toBe('/campanha/apoiadores')
expect(buildSupporterListHref({ page: 1, q: 'ana' }, 2)).toBe(
'/campanha/apoiadores?q=ana&page=2',
)
})
})
describe('resolveSupporterListUrl', () => {
it('is canonical for a clean URL', () => {
const result = resolveSupporterListUrl({ voteIntention: 'indeciso' })
expect(result.state.voteIntention).toBe('indeciso')
expect(result.href).toBe('/campanha/apoiadores?voteIntention=indeciso')
expect(result.redirectHref).toBeUndefined()
})
it('redirects away from unsupported params and clamps the page', () => {
const unsupported = resolveSupporterListUrl({ foo: 'bar' })
expect(unsupported.redirectHref).toBe('/campanha/apoiadores')
const clamped = resolveSupporterListUrl({ page: '99' }, 4)
expect(clamped.state.page).toBe(4)
expect(clamped.redirectHref).toBe('/campanha/apoiadores?page=4')
})
})
describe('getSupporterScopeLabel', () => {
it('pluralizes by count', () => {
expect(getSupporterScopeLabel(1)).toMatch(/^1 apoiador /)
expect(getSupporterScopeLabel(2)).toMatch(/^2 apoiadores /)
})
})
describe('canAccessSupporterArea', () => {
it('allows staff roles and blocks leaders', () => {
expect(canAccessSupporterArea('coordinator')).toBe(true)
expect(canAccessSupporterArea('advisor')).toBe(true)
expect(canAccessSupporterArea('candidate')).toBe(true)
expect(canAccessSupporterArea('leader')).toBe(false)
})
})