mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
B71: polish home search results (bleed hover, list-none, sentence-case headings).
Centralize layout tokens in homeSearchUi.ts so hit rows fill the scroll padding on hover/focus and group lists drop public-site bullet leakage.
This commit is contained in:
parent
5b27608aac
commit
03bcf2e719
12 changed files with 140 additions and 56 deletions
|
|
@ -7,6 +7,7 @@ alwaysApply: false
|
|||
|
||||
## Status
|
||||
|
||||
- **B71 entregue em código (2026-07-30):** polimento visual dos resultados de busca no Início (UX-1) — `src/lib/homeSearchUi.ts` (`HOME_SEARCH_HIT_ROW_WRAPPER_CLASS` = bleed + hover + `focus-within`; heading/list); `HomeSearchHitRow` faixa full-bleed `-mx-4 px-4 md:-mx-6 md:px-6` (mantém `onMouseDown` preventDefault de B66); todos os `HomeSearch*Group` com `ul list-none` e título `text-xs` sentence-case (sem `uppercase`/`tracking-wide`). Unit `homeSearchUi.unit.spec.tsx`. Sem migration/action/JSON. Plano: [`polimento-resultados-busca-inicio.md`](../../../docs/plans/polimento-resultados-busca-inicio.md).
|
||||
- **B66 entregue em código (2026-07-30):** modo focado da busca no **focus** (emenda B47) — `homeSearchUiFocused` (`inputFocused || query.isActive`) já no contrato/hook; overlap B68 (sugestões no focus vazio). **Nesta entrega:** `CampaignHomeLayout` retrai summary+spacer (`data-slot="home-chrome"`) e actions com grid `0fr/1fr` + opacity 220ms (`motion-reduce:transition-none`) em vez de `hidden`; `md:flex-none` no chrome; `HomeSearchHitRow` `onMouseDown` preventDefault (blur→click); e2e focus sem digitar + regressão com digitação. Sem migration. Plano: [`modo-focado-busca-no-focus.md`](../../../docs/plans/modo-focado-busca-no-focus.md).
|
||||
- **B61 entregue em código (2026-07-29):** etapa de ajuste de votos no wizard A1 — `WizardExpectedVotesStep` substitui o stub B60 em `atualizar-votos` com `?municipio=`; três passos explícitos média→pessimista→otimista via `?cenario=`; atalhos `2×`/±50/±100; validação client com jump+warning (`getWizardVoteViolation`); **um POST batch** ao concluir otimista (`POST /campanha/municipios/expected-votes`). Helpers em `wizardVoteEstimate.ts` + `wizardActionHref` estendido. Sem migration/Consent. Unit `wizardVoteEstimate`; e2e avanço de cenário + violação. Plano: [`ajuste-votos-wizard.md`](../../../docs/plans/ajuste-votos-wizard.md). Desbloqueia wiring A1 / **B64** (prefill votos).
|
||||
- **B62 entregue em código (2026-07-29):** modelo de sinal simplificado — `municipalityUpdate` kind `sinal` agora é só `signalType` + `body`; migration `20260730_010601_simplify_municipality_signal_fields` dropa `signal_source`/`triangulated` (o gerador reemitiu `ADD VALUE 'adiada'` por drift de snapshot — removido à mão, e o snapshot novo sara a cadeia); labels/descriptions dos 5 tipos reescritas para a mesa (`Rede esfriou`, `Adversário apareceu`, `Alguém pediu algo` — sem "broker" no modelo de sinal; `activity.origin` `pedido_broker` e a copy do suggestionCatalog ficaram fora por decisão da sessão). Forms: `MunicipalitySignalFields` (lista B26) e o bloco inline de `MunicipalityUpdateForm` perderam Fonte/Triangulado; feed/dossiê (`MunicipalityUpdateFeed` + `municipalityUpdatePageData`) só exibem o badge do tipo. **E11: presença de sinal de adversário lê como confirmada — triage 1** (decisão do usuário: "eles não vão adicionar sinais improváveis"), `adversarySignal: { present: true } | null`, fator único "Sinal de adversário registrado", glossário E18 alinhado. Fixa B63. Bônus: teste e2e `campaignMunicipalities` "advisor scopes…" estava obsoleto desde B43 (home da liderança) — atualizado para `/campanha/contatos` + redirect pós-B43, e o pin de bypass do `municipalityElectoralBaseline` baixado 9→8 (drift pré-existente). Gate: tsc/lint/format/cycles/knip(P3 pré-existente)/876 unit/489 int/e2e alvo verde/build (`/campanha` 233 kB); Aikido 0 findings. Plano: [`simplificar-modelo-sinal.md`](../../../docs/plans/simplificar-modelo-sinal.md). Desbloqueia **B63** (wizard registrar sinal).
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ Backlog consolidado (bloqueadores, site, campanha, white-label): [`docs/roadmap.
|
|||
|
||||
**Recently resolved (2026-07-25): Engineering Consolidation Pass 2** (tracker: [`docs/IMPROVE-CODE-QUALITY-PLAN.md`](docs/IMPROVE-CODE-QUALITY-PLAN.md) § Pass 2; architecture: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md); agent map: `.cursor/rules/codebase-map.mdc`). Highlights: **W1 sistema de listas** — colunas como dado em `CampaignTable` (seams B17/B18), URL state compartilhado (`campaignListUrl` + módulos por domínio; o god module `municipalityUi.ts` virou `municipalityListUrl`/`municipalityListFilters`/`municipalityLabels`/`municipalitySignal`), shells (`CampaignListFooter`, `CampaignListEmptyState`), 8 superfícies migradas (municípios, lideranças, organizações, dobradinhas, demandas, apoiadores, assessores, atividades-shells), B16+ absorvido (`useOptimistic`, hrefs por serializador canônico, facet por slugs, facets no mesmo `Promise.all`); **W2** — fronteiras: `slug`/`phone`/`wordStartFilter`/`voteEstimate` movidos para `lib/`, 21 loaders `server-only`, `campaignRoles.ts` client-safe (sidebar sem o barrel de access), `votePledgeViews` (contract) vs `votePledgeData` (loaders), ciclo supporter quebrado, `components/campaign` em 15 subpastas de domínio; decisão D1: sem `src/domains/`, sem ports-and-adapters; **W4a** — `electionInsights.ts` (941 linhas, 2 exports vivos) deletado; sobreviventes em `electionFormat.ts`/`voteTrend.ts`; E10 nasce limpo; **W4b** — knip `exports`/`types`/`enumMembers` em **ERROR** no CI (0 findings; kit ui sem peças mortas); **W4c** — tabs das páginas de detalhe extraídas (`MunicipalityDetailTabs`, `ActivityOverviewTab`) + factory `detailTabUi`; **W4d** — `runCampaignFormAction` fecha o C8 F4 (13 ações em 7 arquivos; exceções documentadas); **W4e** — tipos de fonte única; **W4f** — copy "Praça"→"Município" varrida (apoiadores desambiguado: cidade do contato = "Cidade"); **D3** — consent do WhatsApp por chave estável (`whatsapp-inscricao`, fail-closed). Suites: 46 unit / 48 int / 7 e2e.
|
||||
|
||||
**Recently resolved (2026-07-30):** **B71** Polimento visual dos resultados de busca no Início — `src/lib/homeSearchUi.ts` centraliza bleed (`-mx-4 px-4 md:-mx-6 md:px-6`), heading discreto (`text-xs` sentence-case) e `ul list-none`; `HomeSearchHitRow` pinta hover/focus na faixa full-bleed; todos os `HomeSearch*Group` alinhados. Sem migration/action/contrato JSON. Plano: [`docs/plans/polimento-resultados-busca-inicio.md`](docs/plans/polimento-resultados-busca-inicio.md).
|
||||
**Recently resolved (2026-07-29):** **B62** Simplificar modelo de sinal — `municipalityUpdate` kind `sinal` is now `signalType` + `body` only: migration `20260730_010601_simplify_municipality_signal_fields` drops `signal_source` and `triangulated` (the generator re-emitted `ADD VALUE 'adiada'` from snapshot drift — removed by hand; this migration's committed `.json` heals the chain), and the five signal-type labels/descriptions were rewritten for the field team (`Rede esfriou`, `Adversário apareceu`, `Alguém pediu algo` — no "broker" in the signal model; `activity.origin`'s `Pedido de broker` and suggestionCatalog copy were explicitly left out by session decision). `MunicipalitySignalFields` (B26 list control) and the inline block in `MunicipalityUpdateForm` lost Fonte/Triangulado; `municipalityUpdatePageData` + `MunicipalityUpdateFeed` (detail + dossier) render only the type badge. **E11 changed semantics: any adversary signal in the window reads as confirmed — P1 triage 1** (session decision, replacing the triangulated/single-source split), `MunicipalityTriggerInput.adversarySignal: { present: true } | null`, single factor copy, E18 glossary aligned. Bonus gate fixes: the `campaignMunicipalities` "advisor scopes…" e2e was stale since B43 (leader home → `/campanha/contatos`) and was updated, and the `municipalityElectoralBaseline` bypass pin dropped 9→8 (pre-existing main drift). Gate: 876 unit / 489 int / targeted e2e green / build; Aikido 0 findings. Plano: [`docs/plans/simplificar-modelo-sinal.md`](docs/plans/simplificar-modelo-sinal.md).
|
||||
**Recently resolved (2026-07-29):** **B59** Chassis do wizard de campanha — rotas staff em `/campanha/acoes/<slug>` (`campaignActionRoutes.ts`, `campaignActionEntryHref`), layout `acoes/layout.tsx` (gate staff, coluna `max-w-lg`), `CampaignWizardShell` (voltar mobile, caption de município sticky, `trailingAction`, foco no `h1` ao trocar passo), cinco páginas-ponte até B60 e strip do Início com `href` nos fluxos wizard. Sem migration. Plano: [`docs/plans/chassis-wizard-campanha.md`](docs/plans/chassis-wizard-campanha.md).
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Polimento visual dos resultados de busca no Início
|
||||
|
||||
Status: rascunho
|
||||
Atualizado em: 2026-07-29
|
||||
Status: entregue (2026-07-30)
|
||||
Atualizado em: 2026-07-30 — as-built: `src/lib/homeSearchUi.ts` (bleed/heading/list); `HomeSearchHitRow` full-bleed `-mx-4 px-4 md:-mx-6 md:px-6` + hover na faixa; todos os `HomeSearch*Group` com `text-xs` sentence-case (sem `uppercase`) e `ul list-none`; unit `homeSearchUi.unit.spec.tsx`; sem migration.
|
||||
Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha B — **B71**; chassis UX-1 / pós-B48)
|
||||
Impeccable: B — encaixe em `HomeSearchMunicipalityGroup` + `HomeSearchHitRow` (B48 ✓)
|
||||
Appetite: ~0,25–0,5 dia eng (CSS/markup; sem migration, action ou rota)
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -3,6 +3,7 @@
|
|||
import { HomeSearchHitRow } from '@/components/campaign/dashboard/HomeSearchHitRow'
|
||||
import { useHomeSearchResults } from '@/components/campaign/dashboard/HomeSearchResultsContext'
|
||||
import { homeSearchActivityGroupHasHits } from '@/lib/campaignHomeSearchHits'
|
||||
import { HOME_SEARCH_GROUP_HEADING_CLASS, HOME_SEARCH_GROUP_LIST_CLASS } from '@/lib/homeSearchUi'
|
||||
|
||||
export const HomeSearchActivityGroup = () => {
|
||||
const { results } = useHomeSearchResults()
|
||||
|
|
@ -13,11 +14,9 @@ export const HomeSearchActivityGroup = () => {
|
|||
const { activities } = results.data
|
||||
|
||||
return (
|
||||
<section aria-label="Atividades" className="flex flex-col gap-1">
|
||||
<h2 className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Atividades
|
||||
</h2>
|
||||
<ul className="flex flex-col">
|
||||
<section aria-label="Atividades" className="flex flex-col gap-0.5">
|
||||
<h2 className={HOME_SEARCH_GROUP_HEADING_CLASS}>Atividades</h2>
|
||||
<ul className={HOME_SEARCH_GROUP_LIST_CLASS}>
|
||||
{activities.map((hit) => (
|
||||
<li key={hit.id}>
|
||||
<HomeSearchHitRow
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { HomeSearchHitRow } from '@/components/campaign/dashboard/HomeSearchHitRow'
|
||||
import { useHomeSearchResults } from '@/components/campaign/dashboard/HomeSearchResultsContext'
|
||||
import { formatHomeSearchMunicipalityCount } from '@/lib/campaignHomeSearchHits'
|
||||
import { HOME_SEARCH_GROUP_HEADING_CLASS, HOME_SEARCH_GROUP_LIST_CLASS } from '@/lib/homeSearchUi'
|
||||
|
||||
export const HomeSearchAdvisorGroup = () => {
|
||||
const { results } = useHomeSearchResults()
|
||||
|
|
@ -13,11 +14,9 @@ export const HomeSearchAdvisorGroup = () => {
|
|||
if (advisors.length === 0) return null
|
||||
|
||||
return (
|
||||
<section aria-label="Assessores" className="flex flex-col gap-1">
|
||||
<h2 className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Assessores
|
||||
</h2>
|
||||
<ul className="flex flex-col">
|
||||
<section aria-label="Assessores" className="flex flex-col gap-0.5">
|
||||
<h2 className={HOME_SEARCH_GROUP_HEADING_CLASS}>Assessores</h2>
|
||||
<ul className={HOME_SEARCH_GROUP_LIST_CLASS}>
|
||||
{advisors.map((hit) => (
|
||||
<li key={hit.id}>
|
||||
<HomeSearchHitRow
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import Link from 'next/link'
|
|||
import type { ReactNode } from 'react'
|
||||
|
||||
import { MunicipalityPriorityIndicator } from '@/components/campaign/municipality/MunicipalityPriorityIndicator'
|
||||
import { HOME_SEARCH_HIT_ROW_WRAPPER_CLASS } from '@/lib/homeSearchUi'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const HOME_SEARCH_PRIORITY_ICON_SLOT_CLASS = 'flex w-4 shrink-0 justify-center'
|
||||
|
|
@ -21,26 +22,28 @@ export const HomeSearchHitRow = ({
|
|||
trailing?: ReactNode
|
||||
showPriority?: boolean
|
||||
}) => (
|
||||
<Link
|
||||
href={href}
|
||||
onMouseDown={(event) => {
|
||||
// Combobox/list precedent: RelationChipCell — keep input focused until navigation (B66).
|
||||
event.preventDefault()
|
||||
}}
|
||||
className={cn(
|
||||
'flex min-h-11 w-full items-center gap-3 py-2.5 text-left text-foreground',
|
||||
'rounded-md outline-none hover:bg-muted/60 focus-visible:ring-2 focus-visible:ring-ring',
|
||||
)}
|
||||
>
|
||||
<span className={HOME_SEARCH_PRIORITY_ICON_SLOT_CLASS} aria-hidden={!showPriority}>
|
||||
{showPriority ? <MunicipalityPriorityIndicator /> : null}
|
||||
</span>
|
||||
<span className="min-w-0 flex-1">
|
||||
<span className="block truncate font-medium">{primary}</span>
|
||||
{secondary ? (
|
||||
<span className="block truncate text-xs text-muted-foreground">{secondary}</span>
|
||||
) : null}
|
||||
</span>
|
||||
{trailing ? <span className="shrink-0">{trailing}</span> : null}
|
||||
</Link>
|
||||
<div className={HOME_SEARCH_HIT_ROW_WRAPPER_CLASS}>
|
||||
<Link
|
||||
href={href}
|
||||
onMouseDown={(event) => {
|
||||
// Combobox/list precedent: RelationChipCell — keep input focused until navigation (B66).
|
||||
event.preventDefault()
|
||||
}}
|
||||
className={cn(
|
||||
'flex min-h-11 w-full items-center gap-3 py-2.5 text-left text-foreground',
|
||||
'outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
||||
)}
|
||||
>
|
||||
<span className={HOME_SEARCH_PRIORITY_ICON_SLOT_CLASS} aria-hidden={!showPriority}>
|
||||
{showPriority ? <MunicipalityPriorityIndicator /> : null}
|
||||
</span>
|
||||
<span className="min-w-0 flex-1">
|
||||
<span className="block truncate font-medium">{primary}</span>
|
||||
{secondary ? (
|
||||
<span className="block truncate text-xs text-muted-foreground">{secondary}</span>
|
||||
) : null}
|
||||
</span>
|
||||
{trailing ? <span className="shrink-0">{trailing}</span> : null}
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { HomeSearchHitRow } from '@/components/campaign/dashboard/HomeSearchHitRow'
|
||||
import { useHomeSearchResults } from '@/components/campaign/dashboard/HomeSearchResultsContext'
|
||||
import { homeSearchLeadershipGroupHasHits } from '@/lib/campaignHomeSearchHits'
|
||||
import { HOME_SEARCH_GROUP_HEADING_CLASS, HOME_SEARCH_GROUP_LIST_CLASS } from '@/lib/homeSearchUi'
|
||||
|
||||
export const HomeSearchLeadershipGroup = () => {
|
||||
const { results } = useHomeSearchResults()
|
||||
|
|
@ -13,11 +14,9 @@ export const HomeSearchLeadershipGroup = () => {
|
|||
if (!homeSearchLeadershipGroupHasHits(results.data)) return null
|
||||
|
||||
return (
|
||||
<section aria-label="Lideranças" className="flex flex-col gap-1">
|
||||
<h2 className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Lideranças
|
||||
</h2>
|
||||
<ul className="flex flex-col">
|
||||
<section aria-label="Lideranças" className="flex flex-col gap-0.5">
|
||||
<h2 className={HOME_SEARCH_GROUP_HEADING_CLASS}>Lideranças</h2>
|
||||
<ul className={HOME_SEARCH_GROUP_LIST_CLASS}>
|
||||
{leaderships.map((hit) => (
|
||||
<li key={`leadership-${hit.id}`}>
|
||||
<HomeSearchHitRow
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { HomeSearchMunicipalityVoteTrailing } from '@/components/campaign/dashbo
|
|||
import { useHomeSearchResults } from '@/components/campaign/dashboard/HomeSearchResultsContext'
|
||||
import { homeSearchMunicipalityGroupHasHits } from '@/lib/campaignHomeSearchHits'
|
||||
import { formatElectionNumber } from '@/lib/electionFormat'
|
||||
import { HOME_SEARCH_GROUP_HEADING_CLASS, HOME_SEARCH_GROUP_LIST_CLASS } from '@/lib/homeSearchUi'
|
||||
import { buildTerritoryPageHref } from '@/lib/territoryAnchor'
|
||||
|
||||
export const HomeSearchMunicipalityGroup = () => {
|
||||
|
|
@ -18,11 +19,9 @@ export const HomeSearchMunicipalityGroup = () => {
|
|||
const sectionTitle = resultKind === 'suggest' ? 'Sugestões' : 'Municípios'
|
||||
|
||||
return (
|
||||
<section aria-label={sectionTitle} className="flex flex-col gap-1">
|
||||
<h2 className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||
{sectionTitle}
|
||||
</h2>
|
||||
<ul className="flex flex-col">
|
||||
<section aria-label={sectionTitle} className="flex flex-col gap-0.5">
|
||||
<h2 className={HOME_SEARCH_GROUP_HEADING_CLASS}>{sectionTitle}</h2>
|
||||
<ul className={HOME_SEARCH_GROUP_LIST_CLASS}>
|
||||
{municipalities.map((hit) => (
|
||||
<li key={`municipality-${hit.slug}`}>
|
||||
<HomeSearchHitRow
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
formatHomeSearchMunicipalityCount,
|
||||
homeSearchStateDeputyGroupHasHits,
|
||||
} from '@/lib/campaignHomeSearchHits'
|
||||
import { HOME_SEARCH_GROUP_HEADING_CLASS, HOME_SEARCH_GROUP_LIST_CLASS } from '@/lib/homeSearchUi'
|
||||
|
||||
const formatStateDeputySecondary = (
|
||||
party: string | null,
|
||||
|
|
@ -26,11 +27,9 @@ export const HomeSearchStateDeputyGroup = () => {
|
|||
if (!homeSearchStateDeputyGroupHasHits(results.data)) return null
|
||||
|
||||
return (
|
||||
<section aria-label="Dobradinhas" className="flex flex-col gap-1">
|
||||
<h2 className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Dobradinhas
|
||||
</h2>
|
||||
<ul className="flex flex-col">
|
||||
<section aria-label="Dobradinhas" className="flex flex-col gap-0.5">
|
||||
<h2 className={HOME_SEARCH_GROUP_HEADING_CLASS}>Dobradinhas</h2>
|
||||
<ul className={HOME_SEARCH_GROUP_LIST_CLASS}>
|
||||
{stateDeputies.map((hit) => (
|
||||
<li key={`state-deputy-${hit.slug}`}>
|
||||
<HomeSearchHitRow
|
||||
|
|
|
|||
8
src/lib/homeSearchUi.ts
Normal file
8
src/lib/homeSearchUi.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/** Mirrors `p-4` / `md:p-6` on `campanha/(app)/layout.tsx` for full-bleed hit rows. */
|
||||
export const HOME_SEARCH_HIT_BLEED_CLASS = '-mx-4 px-4 md:-mx-6 md:px-6'
|
||||
|
||||
export const HOME_SEARCH_HIT_ROW_WRAPPER_CLASS = `${HOME_SEARCH_HIT_BLEED_CLASS} hover:bg-muted/60 focus-within:bg-muted/60`
|
||||
|
||||
export const HOME_SEARCH_GROUP_HEADING_CLASS = 'text-xs font-normal text-muted-foreground'
|
||||
|
||||
export const HOME_SEARCH_GROUP_LIST_CLASS = 'm-0 list-none p-0 [&>li]:mt-0'
|
||||
76
tests/unit/homeSearchUi.unit.spec.tsx
Normal file
76
tests/unit/homeSearchUi.unit.spec.tsx
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import { render, screen } from '@testing-library/react'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { HomeSearchHitRow } from '@/components/campaign/dashboard/HomeSearchHitRow'
|
||||
import { HomeSearchMunicipalityGroup } from '@/components/campaign/dashboard/HomeSearchMunicipalityGroup'
|
||||
import { HomeSearchResultsProvider } from '@/components/campaign/dashboard/HomeSearchResultsContext'
|
||||
import type { HomeSearchSuccessResponse } from '@/lib/campaignHomeSearchHits'
|
||||
import {
|
||||
HOME_SEARCH_GROUP_HEADING_CLASS,
|
||||
HOME_SEARCH_GROUP_LIST_CLASS,
|
||||
HOME_SEARCH_HIT_ROW_WRAPPER_CLASS,
|
||||
} from '@/lib/homeSearchUi'
|
||||
|
||||
const searchResultsValue = (
|
||||
data: Partial<HomeSearchSuccessResponse> = {},
|
||||
resultKind: HomeSearchSuccessResponse['resultKind'] = 'search',
|
||||
) => ({
|
||||
results: {
|
||||
status: 'success' as const,
|
||||
data: {
|
||||
status: 'success' as const,
|
||||
resultKind,
|
||||
municipalities: [],
|
||||
territories: [],
|
||||
advisors: [],
|
||||
leaderships: [],
|
||||
stateDeputies: [],
|
||||
activities: [],
|
||||
...data,
|
||||
},
|
||||
},
|
||||
isFetching: false,
|
||||
resultKind,
|
||||
})
|
||||
|
||||
describe('HomeSearchHitRow', () => {
|
||||
it('wraps the link in a full-bleed hover strip', () => {
|
||||
const { container } = render(
|
||||
<HomeSearchHitRow href="/campanha/municipios/cairu" primary="Cairu" secondary="Recôncavo" />,
|
||||
)
|
||||
|
||||
const bleed = container.firstElementChild
|
||||
expect(bleed?.className).toBe(HOME_SEARCH_HIT_ROW_WRAPPER_CLASS)
|
||||
expect(screen.getByRole('link', { name: /Cairu/i }).className).not.toContain('rounded-md')
|
||||
})
|
||||
})
|
||||
|
||||
describe('HomeSearchMunicipalityGroup', () => {
|
||||
it('renders a discreet sentence-case heading and list without bullets', () => {
|
||||
const { container } = render(
|
||||
<HomeSearchResultsProvider
|
||||
value={searchResultsValue({
|
||||
municipalities: [
|
||||
{
|
||||
kind: 'municipality',
|
||||
slug: 'cairu',
|
||||
name: 'Cairu',
|
||||
region: 'Recôncavo',
|
||||
priority: null,
|
||||
votePosition2022: null,
|
||||
},
|
||||
],
|
||||
})}
|
||||
>
|
||||
<HomeSearchMunicipalityGroup />
|
||||
</HomeSearchResultsProvider>,
|
||||
)
|
||||
|
||||
const heading = screen.getByRole('heading', { name: 'Municípios' })
|
||||
expect(heading.className).toBe(HOME_SEARCH_GROUP_HEADING_CLASS)
|
||||
expect(heading.className).not.toContain('uppercase')
|
||||
|
||||
const list = container.querySelector('ul')
|
||||
expect(list?.className).toBe(HOME_SEARCH_GROUP_LIST_CLASS)
|
||||
})
|
||||
})
|
||||
Loading…
Reference in a new issue