teqo-backup/tests/unit/sharedSheetHostConventions.unit.spec.ts
Francisco Solla 0bb8a96485 feat(campanha): B155+ — migrar quick-edits de célula de lideranças para rota JSON (célula → rota)
F2: POST /campanha/liderancas/state-deputies substitui
setLeadershipStateDeputyMembershipFormAction (chips de /campanha/liderancas B31
e /campanha/dobradinhas B36 — mesma action record).
F3: POST /campanha/liderancas/municipalities substitui
setLeadershipMunicipalitiesFormAction (B34).
Wrappers 'use client' LeadershipStateDeputiesColumnCell /
LeadershipMunicipalitiesColumnCell mantêm o contrato (state, formData) das
shared cells (intocadas); rotas reusam os schemas exportados + allowlists
floor/cap/scope; revalidate herdado das actions record (contrato B34/B31).
F1 (sinal de municípios) não existe mais: C87 o substituiu por form
multi-campo, que por regra B155 permanece em server action — registrado
como já resolvido no plano de intenção.
Guards: whitelist sharedSheetHostConventions (+2 wrappers), prewarm e2e
(+2 rotas), B34 aponta para a rota nova. Sem migration/UI (Impeccable A).

Closes #368
2026-08-24 18:14:56 -03:00

57 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { readdirSync, readFileSync } from 'node:fs'
import { relative, resolve } from 'node:path'
import { describe, expect, it } from 'vitest'
// Miss #52 (2026-07-30): the municipalities list hydrated ~125 idle Drawer
// roots (25 rows × 5 sheet controls) and prod tripped React #130 — CSS
// `display:none` does not remove hydration cost. The fix pattern is ONE
// shared Drawer per list surface via `CampaignListSheetProvider`, with cell
// bodies portaled into it. The provider reached the municípios mobile cards
// and this pass (2026-07-31) the three chip-relation lists (lideranças,
// dobradinhas, assessores) — this guard keeps the next chip-cell table from
// mounting sheet overlays providerless.
describe('shared sheet host for chip-relation cells (miss #52)', () => {
const componentRoots = ['src/components', 'src/app'] as const
const chipCellUsage = /<MunicipalityPortfolioCell|<LeadershipStateDeputyRelationCell/
/**
* Composition wrappers that render a chip cell but are not list surfaces
* themselves: the guard's contract is "the TABLE that mounts chip cells is
* wrapped in the provider", and these wrappers are mounted inside such a
* table (their owning page holds the provider — checked for the C116 people
* list like the dobradinhas one).
*/
const cellWrapperFiles = new Set([
// C128 people list; C116 batch-chip expansion state — the owning page
// holds the provider.
'src/components/campaign/people/PeopleMunicipalityCell.tsx',
// B155+ route-backed column adapters — the owning pages hold the provider.
'src/components/campaign/leadership/LeadershipMunicipalitiesColumnCell.tsx',
'src/components/campaign/leadership/LeadershipStateDeputiesColumnCell.tsx',
])
it('wraps every chip-relation table in CampaignListSheetProvider', () => {
const offenders: string[] = []
for (const root of componentRoots) {
const files = readdirSync(resolve(process.cwd(), root), {
recursive: true,
withFileTypes: true,
})
.filter((entry) => entry.isFile() && entry.name.endsWith('.tsx'))
.map((entry) => resolve(entry.parentPath, entry.name))
for (const file of files) {
const source = readFileSync(file, 'utf8')
if (!chipCellUsage.test(source)) continue
if (source.includes('CampaignListSheetProvider')) continue
if (cellWrapperFiles.has(relative(process.cwd(), file))) continue
offenders.push(relative(process.cwd(), file))
}
}
expect(
offenders,
'chip-relation cells open sheet overlays on coarse pointers — wrap the table in CampaignListSheetProvider (one shared Drawer per list)',
).toEqual([])
})
})