teqo-backup/tests/unit/campaignPageChrome.unit.spec.ts
Francisco Solla cb61cf1152 feat(C211): Central de Conteúdos interna — envio em lote, link, catalogação e publicação
Envio em lote (1 request raw-body por arquivo, fan-out ≤2, até 50 arquivos) e
adicionar por link (Instagram/YouTube; extração só pela Graph API da conta
própria, senão peça-link) em /campanha/comunicacao/conteudos. Cada peça tem
estado próprio (Processando/Pronto/Falhou + Reprocessar), transcrição/texto e
catalogação automática revisável; publicar/despublicar preserva arquivo, slug
e publishedAt.

- collections contentPiece + contentMedia (upload privado no S3) e migration
  20260923_032714_add_content_piece (slug único gerado no 1º publish,
  sourceUrl única, searchText com índice trigram)
- pipeline reusa C199 (job after() + reaper + retry condicional, transcrição
  DeepInfra, ffmpeg/chunk), o classificador de facetas do acervo e o
  institutionCatalog; curatedFields impede o job de sobrescrever curadoria
- gate único canReadCommunicationCatalog (advisor/leader negados); delete
  só pelo admin; sem Consent novo
- UI portada do design aprovado (lista desktop + cards mobile, diálogo de
  lote com progresso por arquivo, diálogo de link, ficha editável, kill
  switch); nav/chrome/column-picker/manifest atualizados
- instagramFeed expõe mediaUrl; revalidateTag ganha wrapper seguro fora de
  request (fixtures/scripts)
- testes: 2 unit specs, 1 int spec (16 casos) e 7 e2e na vertical
- follow-up de engenharia: #1267 (docs/plans/escala-dry-pos-c211.md)

Closes #1254
2026-09-23 02:25:15 -03:00

108 lines
4.5 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
campaignPageMetadata,
campaignPageMetadataFromCatalog,
resolveCampaignPageChrome,
} from '@/lib/campaignPageChrome'
describe('campaignPageChrome', () => {
it('returns null for home', () => {
expect(resolveCampaignPageChrome('/campanha', 'coordinator')).toBeNull()
expect(resolveCampaignPageChrome('/campanha/', 'advisor')).toBeNull()
})
it('resolves section list chrome without prose subtitle', () => {
expect(resolveCampaignPageChrome('/campanha/municipios', 'coordinator')).toEqual({
title: 'Municípios',
})
expect(resolveCampaignPageChrome('/campanha/liderancas', 'advisor')).toEqual({
title: 'Lideranças',
})
expect(resolveCampaignPageChrome('/campanha/agenda', 'coordinator')).toEqual({
title: 'Agenda',
})
})
it('returns null for entity detail pages (chrome set per route)', () => {
expect(resolveCampaignPageChrome('/campanha/municipios/cairu', 'coordinator')).toBeNull()
expect(resolveCampaignPageChrome('/campanha/liderancas/42', 'advisor')).toBeNull()
expect(resolveCampaignPageChrome('/campanha/atividades/foo', 'coordinator')).toBeNull()
})
it('keeps section title on parallel municipio v2 route (B147 soft-dep)', () => {
expect(resolveCampaignPageChrome('/campanha/municipio/cairu/v2', 'coordinator')).toEqual({
title: 'Municípios',
})
})
it('resolves quadro without role-based prose subtitle', () => {
expect(resolveCampaignPageChrome('/campanha/quadro', 'advisor')).toEqual({ title: 'Quadro' })
expect(resolveCampaignPageChrome('/campanha/quadro', 'coordinator')).toEqual({
title: 'Quadro',
})
})
it('keeps prose subtitle on out-of-scope sections', () => {
expect(resolveCampaignPageChrome('/campanha/conceitos', 'coordinator')?.subtitle).toContain(
'cada número',
)
expect(resolveCampaignPageChrome('/campanha/perfil', 'coordinator')?.subtitle).toContain(
'biometria',
)
})
it('builds tab metadata from catalog', () => {
expect(campaignPageMetadataFromCatalog('contatos').title).toBe('Contatos')
expect(campaignPageMetadataFromCatalog('meusContatos').title).toBe('Meus contatos')
expect(campaignPageMetadata(null).title).toBe('Início')
})
it('resolves the communication vertical and its acervo (C154)', () => {
expect(resolveCampaignPageChrome('/campanha/comunicacao', 'communicator')).toEqual({
title: 'Comunicação',
})
expect(resolveCampaignPageChrome('/campanha/comunicacao/acervo', 'communicator')).toEqual({
title: 'Acervo de falas',
subtitle: 'Busque nas falas da Câmara ou nas gravações da equipe.',
})
expect(resolveCampaignPageChrome('/campanha/comunicacao/acervo/42', 'communicator')).toBeNull()
// C199 — the recordings alias has its own entry BEFORE the generic detail
// regex, which would otherwise read `gravacoes` as a speech id.
expect(
resolveCampaignPageChrome('/campanha/comunicacao/acervo/gravacoes', 'communicator'),
).toEqual({ title: 'Gravações enviadas' })
expect(
resolveCampaignPageChrome('/campanha/comunicacao/acervo/gravacoes/7', 'communicator'),
).toBeNull()
})
it('resolves the reel library list and leaves the detail title to the page (C194)', () => {
expect(resolveCampaignPageChrome('/campanha/comunicacao/reels', 'communicator')).toEqual({
title: 'Reels',
subtitle: 'Tutoriais do site prontos para a assessoria baixar e publicar fora do Teqo.',
})
expect(resolveCampaignPageChrome('/campanha/comunicacao/reels/42', 'communicator')).toBeNull()
})
it('resolves the content Central list and leaves the ficha title to the page (C211)', () => {
expect(resolveCampaignPageChrome('/campanha/comunicacao/conteudos', 'communicator')).toEqual({
title: 'Conteúdos',
subtitle: 'Peças que alimentam a Central pública.',
})
expect(
resolveCampaignPageChrome('/campanha/comunicacao/conteudos/42', 'communicator'),
).toBeNull()
})
it('separates staff contatos from the leader meus-contatos (C139)', () => {
expect(resolveCampaignPageChrome('/campanha/contatos', 'coordinator')).toEqual({
title: 'Contatos',
subtitle: 'Fichas da campanha — atualize dados e fale com as pessoas.',
})
expect(resolveCampaignPageChrome('/campanha/meus-contatos', 'leader')).toEqual({
title: 'Meus contatos',
subtitle: 'Cadastre apoiadores pelo celular. Só você vê os contatos que criou aqui.',
})
})
})