teqo-backup/tests/int/contactPhoneNormalization.int.spec.ts
Francisco Ignácio Fontoura Solla cf13c441aa Remodel /campanha around predefined Praças replacing electoral nuclei.
436 seeded Praças (municipality-based; per-TSE-zone in Salvador/Camaçari) become
the operational unit; roles renamed to coordinator/advisor/leader with advisors
scoped to administered Praças. Leadership is one record per person across many
Praças/organizations; vote pledges split leader-declared vs staff-estimated
(estimates never serialized to leaders). Adds organizations, demand workflow
with staff-only cost/receipts, action-plan results with deputy presence, manual
political trend, multi-candidate comparison and the diverging red/white/blue
map mode. Migration 20260721_020109_remodel_plazas deliberately resets the
campaign vertical in production (public site untouched); test suite ported to
the new model (unit 187 / int 306 / e2e 9 green).
2026-07-21 02:28:00 -03:00

62 lines
2 KiB
TypeScript

// @vitest-environment node
import { beforeEach, describe, expect, it, vi } from 'vitest'
const phoneMocks = vi.hoisted(() => ({
normalizeBrazilianPhone: vi.fn<(value: string) => string | null>(),
}))
vi.mock('@/utilities/phone', async (importOriginal) => {
const actual = await importOriginal<typeof import('@/utilities/phone')>()
phoneMocks.normalizeBrazilianPhone.mockImplementation(actual.normalizeBrazilianPhone)
return {
...actual,
normalizeBrazilianPhone: phoneMocks.normalizeBrazilianPhone,
}
})
import { Contact } from '@/collections/Contact'
import { leadershipCreateSchema } from '@/lib/schemas/leadership'
const contactPhoneHook = Contact.hooks?.beforeValidate?.[0]
const runContactPhoneHook = async (phone: string) => {
if (typeof contactPhoneHook !== 'function') {
throw new Error('Expected Contact.beforeValidate phone hook.')
}
const data = { phone }
await contactPhoneHook({ data } as never)
return data.phone
}
describe('Contact phone normalization boundary', () => {
beforeEach(() => {
phoneMocks.normalizeBrazilianPhone.mockClear()
})
it('normalizes once before leadership dedupe and skips canonical Contact input', async () => {
const parsed = leadershipCreateSchema.parse({
plazas: [1],
name: 'Liderança normalizada',
phone: '+55 (71) 99999-1234',
})
expect(parsed.phone).toBe('71999991234')
expect(await runContactPhoneHook(parsed.phone)).toBe('71999991234')
expect(phoneMocks.normalizeBrazilianPhone).toHaveBeenCalledTimes(1)
})
it('normalizes a formatted phone sent directly to the Contact API boundary', async () => {
expect(await runContactPhoneHook('+55 (71) 99999-1234')).toBe('71999991234')
expect(phoneMocks.normalizeBrazilianPhone).toHaveBeenCalledTimes(1)
})
it('rejects an invalid canonical-length direct API phone without re-normalizing it', async () => {
await expect(runContactPhoneHook('00000000000')).rejects.toThrow(
'Celular brasileiro inválido.',
)
expect(phoneMocks.normalizeBrazilianPhone).not.toHaveBeenCalled()
})
})