teqo-backup/tests/unit/campaignPageChromeText.unit.spec.tsx
Francisco Solla f3c41d3382 feat(C101-ux): agenda mobile — navegação por teclado (região focável) + affordance do tap no título
- useAgendaKeyboardNavigation: ArrowLeft/Right → prev/next no mobile
  (FullCalendar v7 não tem setas no grid — verificado no bundle); skips
  para modificadores/dialog/menu/inputs; restore de foco na região
- Região de teclado mobile-only: tabIndex/role/aria-label gateados por
  isMobile (desktop mantém a toolbar e sua árvore a11y intacta)
- onTitleClick ganha icon?: LucideIcon (glyph da página, aria-hidden);
  agenda passa RotateCcw como affordance do 'voltar para hoje'
- E2E: teste de teclado (dia e mês), glyph no título, hardening do swipe
  CDP (pacing 25ms — burst era classificado como flick pelo Chromium e
  disparava back-nav ~35% das runs)
- Unit: 14 testes do hook/pura + 4 do renderer do glyph; impl plan
  docs/plans/c101-ux-pos-critique-impl.md (aprovado pelo humano)

Closes #512
2026-08-10 00:53:19 -03:00

65 lines
2.1 KiB
TypeScript

import { cleanup, render, screen } from '@testing-library/react'
import { CalendarDays } from 'lucide-react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { CampaignPageChromeText } from '@/components/campaign/shell/CampaignPageChromeText'
afterEach(() => {
cleanup()
vi.restoreAllMocks()
})
describe('CampaignPageChromeText (mobile)', () => {
it('renderiza o título como botão quando há onTitleClick', () => {
const action = vi.fn()
render(
<CampaignPageChromeText
layout="mobile"
chrome={{ title: '9 Agosto', onTitleClick: { action, hint: 'Voltar para hoje' } }}
/>,
)
const button = screen.getByRole('button', { name: '9 Agosto' })
button.click()
expect(action).toHaveBeenCalled()
// Sem `icon` no contrato, o botão não renderiza glyph nenhum.
expect(button.querySelector('svg')).toBeNull()
})
it('renderiza o glyph do affordance (aria-hidden) quando onTitleClick.icon existe', () => {
render(
<CampaignPageChromeText
layout="mobile"
chrome={{
title: '9 Agosto',
onTitleClick: { action: vi.fn(), hint: 'Voltar para hoje', icon: CalendarDays },
}}
/>,
)
const button = screen.getByRole('button', { name: '9 Agosto' })
const icon = button.querySelector('svg')
expect(icon).not.toBeNull()
expect(icon?.getAttribute('aria-hidden')).toBe('true')
})
it('não renderiza glyph sem icon no contrato', () => {
render(<CampaignPageChromeText layout="mobile" chrome={{ title: 'Agenda' }} />)
expect(screen.queryByRole('button')).toBeNull()
expect(screen.getByText('Agenda')).toBeTruthy()
})
})
describe('CampaignPageChromeText (desktop)', () => {
it('não vira botão nem renderiza glyph — o chrome do desktop é texto', () => {
render(
<CampaignPageChromeText
layout="desktop"
chrome={{
title: '9 Agosto',
onTitleClick: { action: vi.fn(), hint: 'Voltar para hoje', icon: CalendarDays },
}}
/>,
)
expect(screen.queryByRole('button')).toBeNull()
expect(screen.getByText('9 Agosto')).toBeTruthy()
})
})