teqo/tests/unit/municipalityV2StatusView.unit.spec.ts
Francisco Solla 212a1f2423 feat(campaign): C87 — atualização unificada (texto + polaridade + urgente)
Substitui o modelo de MunicipalityUpdate (kind/semanal/urgente/nota/sinal + signalType)
por um modelo unificado: body obrigatório + polarity (boa/neutra/ruim) + urgent + adversarySignal.

- Schema: polarity enum obrigatório, urgent boolean default false, adversarySignal boolean
- Wizard: novo WizardUpdateBodyStep com campo de texto + polaridade + urgente
- Lista: controle unificado de atualização com polaridade inline
- Feed: exibe polaridade como badge colorido + indicador de urgência
- V2 status strip: atualização rápida de polaridade
- E11: queries atualizadas para polarity + adversarySignal
- Migração: 20260807_030000_unify_municipality_update (backfill polarity=neutra, urgent de kind, adversarySignal de kind+signalType)
- Testes: 18/18 integração C87, 593/593 total, 1399/1399 unitários
- Fix: testes de state deputy usavam nomes fixos que colidiam entre execuções
2026-08-07 05:04:41 -03:00

77 lines
2.4 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
buildMunicipalityV2StatusAggregate,
MUNICIPALITY_V2_SIGNAL_COLD_VALUE,
resolveMunicipalityV2UpdateState,
} from '@/utilities/municipality/municipalityV2StatusView'
describe('municipalityV2StatusView', () => {
it('uses cold sentinel when there is no recent signal', () => {
const state = resolveMunicipalityV2UpdateState(
{ polarity: null, lastSignalAt: null },
new Date('2026-08-02T12:00:00.000Z'),
)
expect(state.value).toBe(MUNICIPALITY_V2_SIGNAL_COLD_VALUE)
expect(state.isCold).toBe(true)
expect(state.label).toContain('Sem sinal')
})
it('does not claim frio when frescor is warm but typeless', () => {
const state = resolveMunicipalityV2UpdateState(
{
polarity: null,
lastSignalAt: '2026-08-01T12:00:00.000Z',
},
new Date('2026-08-02T12:00:00.000Z'),
)
expect(state.value).toBe(MUNICIPALITY_V2_SIGNAL_COLD_VALUE)
expect(state.isCold).toBe(false)
expect(state.label).toBe('Sem polaridade')
})
it('keeps the typed polarity when still warm', () => {
const state = resolveMunicipalityV2UpdateState(
{
polarity: 'ruim',
lastSignalAt: '2026-08-01T12:00:00.000Z',
},
new Date('2026-08-02T12:00:00.000Z'),
)
expect(state.value).toBe('ruim')
expect(state.isCold).toBe(false)
expect(state.label).toBe('Ruim')
})
it('builds the aggregate from the three note axes', () => {
const aggregate = buildMunicipalityV2StatusAggregate(
{
engagementLevel: 'n2',
levelNote: 'Subiu o nível',
trendNote: 'Tendência melhor',
updatePolarity: 'ruim',
updateBody: 'Rede parou',
lastSignalAt: '2026-08-01T12:00:00.000Z',
},
new Date('2026-08-02T12:00:00.000Z'),
)
expect(aggregate).toBe('Subiu o nível · Tendência melhor · Rede parou')
})
it('names absences when notes are empty', () => {
const aggregate = buildMunicipalityV2StatusAggregate(
{
engagementLevel: 'n1',
levelNote: null,
trendNote: null,
updatePolarity: null,
updateBody: null,
lastSignalAt: null,
},
new Date('2026-08-02T12:00:00.000Z'),
)
expect(aggregate).toContain('sem motivo')
expect(aggregate).toContain('Tendência sem nota')
expect(aggregate).toContain('Sem sinal')
})
})