mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
Phase 1 UX: StrictCombobox municipality in SupporterForm, AlertDialog in RemoveSupporterDataButton. Phase 2 DRY: campaignListUrl + CampaignListPagination + campaignFormFields + mapCampaignFormActionError shared across nuclei, supporters and action plans. Phase 3: single SQL aggregate for supporter list KPIs via drizzle in the Payload txn. Phase 4: bulk drizzle insert for CSV import inside the existing Payload txn with ON CONFLICT DO NOTHING, plus a fail-closed skipContactPhoneInvariant context flag. Phase 5: HMAC-signed single-use import token backed by a new supporterImportBatch staging collection so the full ok-row set never crosses the Server Action boundary twice.
77 lines
2 KiB
TypeScript
77 lines
2 KiB
TypeScript
// @vitest-environment node
|
|
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
import {
|
|
resolveBahiaMunicipality,
|
|
supporterCreateSchema,
|
|
supporterImportConfirmSchema,
|
|
supporterVoteIntentionSchema,
|
|
} from '@/lib/schemas/supporter'
|
|
|
|
describe('supporter schemas', () => {
|
|
it('normalizes phone and optional BA municipality', () => {
|
|
const parsed = supporterCreateSchema.parse({
|
|
name: 'Maria da Silva',
|
|
phone: '+55 (71) 98888-7777',
|
|
city: 'salvador',
|
|
consentAccepted: true,
|
|
})
|
|
|
|
expect(parsed.phone).toBe('71988887777')
|
|
expect(parsed.city).toBe('Salvador')
|
|
expect(resolveBahiaMunicipality('feira de santana')).toBe('Feira de Santana')
|
|
expect(resolveBahiaMunicipality('Nowhere')).toBeNull()
|
|
})
|
|
|
|
it('requires highlighted consent when vote intention is set on create', () => {
|
|
expect(
|
|
supporterCreateSchema.safeParse({
|
|
name: 'Maria Silva',
|
|
phone: '71988887777',
|
|
voteIntention: 'certo',
|
|
consentAccepted: true,
|
|
}).success,
|
|
).toBe(false)
|
|
|
|
expect(
|
|
supporterCreateSchema.safeParse({
|
|
name: 'Maria Silva',
|
|
phone: '71988887777',
|
|
voteIntention: 'certo',
|
|
consentAccepted: true,
|
|
voteIntentionConsentAccepted: true,
|
|
}).success,
|
|
).toBe(true)
|
|
})
|
|
|
|
it('requires operator attestation and a token for import confirm', () => {
|
|
expect(
|
|
supporterImportConfirmSchema.safeParse({
|
|
importToken: 'token',
|
|
}).success,
|
|
).toBe(false)
|
|
|
|
expect(
|
|
supporterImportConfirmSchema.safeParse({
|
|
operatorAttested: true,
|
|
}).success,
|
|
).toBe(false)
|
|
|
|
expect(
|
|
supporterImportConfirmSchema.parse({
|
|
operatorAttested: true,
|
|
importToken: 'batch.123.sig',
|
|
}).importToken,
|
|
).toBe('batch.123.sig')
|
|
})
|
|
|
|
it('requires vote intention consent acceptance', () => {
|
|
expect(
|
|
supporterVoteIntentionSchema.safeParse({
|
|
id: 1,
|
|
voteIntention: 'indeciso',
|
|
}).success,
|
|
).toBe(false)
|
|
})
|
|
})
|