mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
155 lines
5 KiB
TypeScript
155 lines
5 KiB
TypeScript
import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'
|
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import { PetitionForm } from '@/components/PetitionForm'
|
|
import type { Petition } from '@/payload-types'
|
|
|
|
/**
|
|
* #766 — the `Lead` wiring of the petition form: a successful signature with a
|
|
* configured pixel fires exactly one `trackMetaLead` (content_name = petition
|
|
* title, UUID eventID); without a pixel, or when the submission fails, nothing
|
|
* fires. A tracking hiccup (e.g. `crypto.randomUUID` on a non-secure context)
|
|
* must never turn an already-committed signature into the error UI — the
|
|
* success dialog still shows, preventing a retry that would duplicate the
|
|
* signature and re-fire the `Lead`.
|
|
*/
|
|
const submitPetitionSignatureMock = vi.fn()
|
|
const trackMetaLeadMock = vi.fn()
|
|
|
|
vi.mock('@/app/(frontend)/actions/submitPetitionSignature', () => ({
|
|
submitPetitionSignature: (...args: unknown[]) => submitPetitionSignatureMock(...args),
|
|
}))
|
|
|
|
vi.mock('@/lib/facebookPixel', async (importOriginal) => {
|
|
const actual = await importOriginal<typeof import('@/lib/facebookPixel')>()
|
|
return {
|
|
...actual,
|
|
trackMetaLead: (...args: unknown[]) => trackMetaLeadMock(...args),
|
|
}
|
|
})
|
|
|
|
const PIXEL_ID = '123456789012345'
|
|
|
|
const petition = {
|
|
id: '1',
|
|
title: 'Pela manutenção do Hospital do Subúrbio',
|
|
form: { title: 'Assine a petição', subtitle: '' },
|
|
} as unknown as Petition
|
|
|
|
beforeAll(() => {
|
|
// Radix/Base UI comboboxes (StateSelect/CitySelect) need ResizeObserver in jsdom.
|
|
vi.stubGlobal(
|
|
'ResizeObserver',
|
|
class {
|
|
observe() {}
|
|
unobserve() {}
|
|
disconnect() {}
|
|
},
|
|
)
|
|
})
|
|
|
|
const fillAndSubmit = async () => {
|
|
// FormInput propagates to react-hook-form through the native `input` event.
|
|
fireEvent.input(screen.getByPlaceholderText('Digite seu nome completo'), {
|
|
target: { value: 'Maria Teste' },
|
|
})
|
|
fireEvent.input(screen.getByPlaceholderText('Digite seu e-mail'), {
|
|
target: { value: 'maria@teste.com' },
|
|
})
|
|
fireEvent.input(screen.getByPlaceholderText('(71) 99999-9999'), {
|
|
target: { value: '71987654321' },
|
|
})
|
|
fireEvent.input(screen.getByPlaceholderText('00000-000'), {
|
|
target: { value: '41950000' },
|
|
})
|
|
fireEvent.input(screen.getByPlaceholderText('Selecione um estado'), {
|
|
target: { value: 'BA' },
|
|
})
|
|
fireEvent.click(await screen.findByRole('option', { name: 'Bahia' }))
|
|
fireEvent.input(screen.getByPlaceholderText('Selecione uma cidade'), {
|
|
target: { value: 'Salvador' },
|
|
})
|
|
fireEvent.click(await screen.findByRole('option', { name: 'Salvador' }))
|
|
await act(async () => {
|
|
fireEvent.click(screen.getByRole('button', { name: 'Assinar' }))
|
|
})
|
|
}
|
|
|
|
describe('Petition form Lead wiring', () => {
|
|
beforeEach(() => {
|
|
submitPetitionSignatureMock.mockReset()
|
|
trackMetaLeadMock.mockReset()
|
|
submitPetitionSignatureMock.mockResolvedValue({ ok: true, signatureNumber: 42 })
|
|
})
|
|
|
|
afterEach(() => {
|
|
cleanup()
|
|
})
|
|
|
|
it('fires exactly one Lead on a successful signature with a configured pixel', async () => {
|
|
render(
|
|
<PetitionForm
|
|
id="formulario"
|
|
petition={petition}
|
|
consentHTML=""
|
|
facebookPixelId={PIXEL_ID}
|
|
/>,
|
|
)
|
|
await fillAndSubmit()
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByRole('heading', { name: 'Obrigado por assinar!' })).toBeTruthy()
|
|
})
|
|
expect(trackMetaLeadMock).toHaveBeenCalledTimes(1)
|
|
expect(trackMetaLeadMock).toHaveBeenCalledWith(PIXEL_ID, petition.title, expect.any(String))
|
|
})
|
|
|
|
it('keeps the committed signature a success when tracking throws', async () => {
|
|
trackMetaLeadMock.mockImplementation(() => {
|
|
throw new Error('crypto.randomUUID is not available')
|
|
})
|
|
render(
|
|
<PetitionForm
|
|
id="formulario"
|
|
petition={petition}
|
|
consentHTML=""
|
|
facebookPixelId={PIXEL_ID}
|
|
/>,
|
|
)
|
|
await fillAndSubmit()
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByRole('heading', { name: 'Obrigado por assinar!' })).toBeTruthy()
|
|
})
|
|
expect(submitPetitionSignatureMock).toHaveBeenCalledTimes(1)
|
|
expect(screen.queryByText('Falha ao enviar assinatura. Tente novamente.')).toBeNull()
|
|
})
|
|
|
|
it('never fires a Lead without a configured pixel', async () => {
|
|
render(<PetitionForm id="formulario" petition={petition} consentHTML="" />)
|
|
await fillAndSubmit()
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByRole('heading', { name: 'Obrigado por assinar!' })).toBeTruthy()
|
|
})
|
|
expect(trackMetaLeadMock).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('never fires a Lead when the submission fails', async () => {
|
|
submitPetitionSignatureMock.mockRejectedValue(new Error('boom'))
|
|
render(
|
|
<PetitionForm
|
|
id="formulario"
|
|
petition={petition}
|
|
consentHTML=""
|
|
facebookPixelId={PIXEL_ID}
|
|
/>,
|
|
)
|
|
await fillAndSubmit()
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByText('Falha ao enviar assinatura. Tente novamente.')).toBeTruthy()
|
|
})
|
|
expect(trackMetaLeadMock).not.toHaveBeenCalled()
|
|
})
|
|
})
|