teqo-backup/tests/unit/voteGoals.unit.spec.ts
Francisco Ignácio Fontoura Solla 456b5d8a4e Add nucleus vote goals foundation for E1/E3.
Introduce voteGoals helpers, Metas 2026 UI card, migration, and unit tests as the first slice of scenario goals and priority work.
2026-07-19 04:36:58 -03:00

105 lines
3.6 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { nucleusCreateSchema } from '@/lib/schemas/nucleus'
import { buildNucleusListWhere, parseNucleusListParams } from '@/utilities/nucleusUi'
import { toNucleusDetailViewModel } from '@/utilities/nucleusViewModels'
import {
aggregateVoteGoals,
countHighPriorityNuclei,
getVoteGoalsOrderViolation,
sumVoteGoals,
voteGoalProgressPercent,
} from '@/utilities/voteGoals'
describe('vote goals schema and aggregates', () => {
it('accepts ordered vote goals and priority on create', () => {
const parsed = nucleusCreateSchema.parse({
name: 'Núcleo Metas',
cities: ['Salvador'],
organizationKind: 'territorial',
voteGoals: { good: 1000, regular: 800, minimum: 500 },
priority: 'alta',
})
expect(parsed.voteGoals).toEqual({ good: 1000, regular: 800, minimum: 500 })
expect(parsed.priority).toBe('alta')
})
it('rejects vote goals that break Bom ≥ Regular ≥ Mínimo', () => {
const result = nucleusCreateSchema.safeParse({
name: 'Núcleo inválido',
cities: ['Salvador'],
organizationKind: 'territorial',
voteGoals: { good: 100, regular: 200 },
})
expect(result.success).toBe(false)
})
it('filters list results by alta priority', () => {
expect(parseNucleusListParams({ priority: 'alta' })).toEqual({ page: 1, priority: 'alta' })
expect(buildNucleusListWhere({ page: 1, priority: 'alta' })).toEqual({
and: [{ status: { equals: 'ativo' } }, { priority: { equals: 'alta' } }],
})
})
it('aggregates vote goals and counts high-priority nuclei', () => {
const nuclei = [
{
voteGoals: { good: 1000, regular: 800, minimum: 500 },
priority: 'alta' as const,
},
{
voteGoals: { good: 200, regular: 150, minimum: 100 },
priority: 'normal' as const,
},
]
expect(aggregateVoteGoals(nuclei)).toEqual({
good: 1200,
regular: 950,
minimum: 600,
highPriorityCount: 1,
})
expect(sumVoteGoals(nuclei)).toEqual({ good: 1200, regular: 950, minimum: 600 })
expect(countHighPriorityNuclei(nuclei)).toBe(1)
expect(voteGoalProgressPercent(400, 800)).toBe(50)
expect(voteGoalProgressPercent(null, 800)).toBeNull()
})
it('flags vote goal order violations on sparse inputs', () => {
expect(getVoteGoalsOrderViolation({ good: 100, regular: 200 })).toBe('regular')
expect(getVoteGoalsOrderViolation({ regular: 50, minimum: 100 })).toBe('minimum')
expect(getVoteGoalsOrderViolation({ good: 100, minimum: 200 })).toBe('minimum')
expect(getVoteGoalsOrderViolation({ good: 100, regular: 80 })).toBeNull()
})
it('exposes vote goals to lideranca but omits staff-only strategy notes', () => {
const view = toNucleusDetailViewModel(
{
id: 1,
name: 'Núcleo',
slug: 'nucleo',
status: 'ativo',
cities: ['Salvador'],
regions: ['Metropolitano de Salvador'],
organizationKind: 'territorial',
tseZones: [],
voteGoals: { good: 100, regular: 80, minimum: 50 },
priority: 'alta',
dobradinhaNotes: 'Negociação em curso',
nextSteps: 'Visitar prefeito',
strengths: [{ text: 'Sigiloso' }],
updatedAt: '',
createdAt: '',
},
'lideranca',
)
expect(view.voteGoals).toEqual({ good: 100, regular: 80, minimum: 50 })
expect(view.priority).toBe('alta')
expect(JSON.stringify(view.tabs)).not.toContain('Negociação em curso')
expect(JSON.stringify(view.tabs)).not.toContain('Visitar prefeito')
expect(JSON.stringify(view.tabs)).not.toContain('Sigiloso')
})
})