import { App } from '@inertiajs/react'; import type { Page } from '@inertiajs/core'; import { renderToString } from 'react-dom/server'; import { expect, test } from 'vitest'; import PeopleIndex from '@/pages/people'; import PeopleShow from '@/pages/people/show'; import PeopleAccess from '@/pages/people/access'; import { PeopleClarifications } from '@/components/people-clarifications'; import type { ClarificationData } from '@/components/people-clarifications'; import { PeopleOperationalInsights } from '@/components/people-operational-insights'; const base = { component: 'people/index', url: '/pessoas', version: 'people-regression', props: { errors: {} }, clearHistory: false, encryptHistory: false, } satisfies Page; test('operational reading explains its scope and missing deadlines without suggesting candidate decisions', () => { function Screen() { return ( ); } const html = renderToString( , ); const text = html.replace(//g, ''); expect(text).toContain('2 processos autorizados'); expect(text).toContain('2 prazos vencidos em'); expect(text).toContain('7 dias de calendário'); expect(html).toContain('/pessoas/42#clarification-7'); expect(html).toContain('esta ausência não indica incumprimento'); expect(html).toContain('sem previsão por machine learning'); expect(html).not.toContain(' { const page = { ...base, props: { ...base.props, ready: true, kinds: ['service', 'staff'], canPrepare: ['service', 'staff'], processes: { data: [ { id: 1, title: 'Processo fictício', kind: 'service', status: 'contract_draft', closes_on: '2026-10-30', }, ], links: [], }, }, }; const html = renderToString( , ); expect(html).toContain('Prestador individual'); expect(html).toContain('Trabalhador para o quadro'); expect(html).toContain('Critérios de avaliação'); expect(html).toContain('Minuta contratual preparada'); }); test.each(['service', 'staff'])( 'the %s hiring report and evaluation forms render without object children', (kind) => { const process = { id: 1, title: 'Processo fictício', purpose: 'Âmbito fictício', kind, status: 'assessment', version: 4, closes_on: '2026-10-30', rules: { minimum_reviews: 1, criteria: [{ label: 'Competências', weight: 100 }], }, selection: null, selected_application_id: null, contract: null, }; const page = { ...base, component: 'people/show', props: { ...base.props, process, brief: { method: 'people_evidence_brief_v1', generated_at: '2026-10-30T12:00:00Z', basis_sha256: 'a'.repeat(64), finance_visible: false, claims: [ { id: 'candidates', text: 'Matriz actual, sem selecção automática.', basis_sha256: 'b'.repeat(64), source: { href: '#people-report-candidates', label: 'Candidaturas e avaliação', pointer: 'candidates', }, }, ], }, candidates: [ { id: 1, name: 'Pessoa fictícia', reference: 'CAND-1', summary: 'Resumo profissional fictício', received_on: '2026-10-30', evaluation_count: 0, score_minor: null, reviews: [], }, ], canPrepare: true, canReview: true, history: [], }, }; const html = renderToString( , ); expect(html).toContain('Registar avaliação'); expect(html).toContain('Propor selecção'); expect(html).toContain('Pessoa fictícia'); expect(html).toContain('Síntese com fontes'); expect(html).toContain('href="#people-report-candidates"'); expect(html).toContain('id="people-report-candidates"'); expect(html).toContain('id="people-report-scope"'); }, ); test('team configuration renders without requiring or displaying candidate content', () => { const page = { ...base, component: 'people/access', props: { ...base.props, process: { id: 1, kind: 'staff', status: 'assessment' }, version: 3, scopes: { view: 'Consultar processo', approve: 'Decidir selecção' }, users: [{ id: 1, name: 'Responsável fictício' }], assignments: [ { user_id: 1, scopes: ['view'], expires_at: '2030-01-01 12:00:00', }, ], canView: false, }, }; const html = renderToString( , ); expect(html).toContain('Responsável fictício'); expect(html).not.toContain('href="/pessoas/1"'); expect(html).toContain('Guardar atribuição'); }); test('personal tasks and approvals render as separate queues linked to original processes', () => { const item = { id: '1:evaluate:99', process_id: 1, reference: 'PES-1', title: 'Vaga fictícia', kind: 'staff', status: 'assessment', action: 'evaluate', label: 'Avaliar candidatura #99', due_on: null, href: '/pessoas/1?candidatura=99#people-evaluate', }; const page = { ...base, props: { ...base.props, ready: true, kinds: ['staff'], canPrepare: [], processes: { data: [], links: [] }, company: { name: 'Entidade fictícia' }, workdesk: { updated_at: '2026-10-30T12:00:00Z', counts: { processes: 1, active: 1, contract_drafts: 0, tasks: 1, approvals: 0, overdue: 0, }, tasks: [item], approvals: [], alerts: [], }, }, }; const html = renderToString( , ); expect(html).toContain('As minhas tarefas'); expect(html).toContain('Sem decisões formais pendentes'); expect(html).toContain('href="/pessoas/1?candidatura=99#people-evaluate"'); expect(html).toContain('Entidade fictícia'); expect(html).toContain('Actualizar'); }); test('assigned clarification response renders without requiring broader interview access', () => { const data: ClarificationData = { ready: true, sources: [], users: [], items: [ { id: 7, application_id: 1, version: 1, status: 'open', due_on: '2026-10-30', outcome: null, question: 'Confirmar o comprovativo documental.', canRespond: true, canReview: false, canReassign: false, responses: [], decisions: [], }, ], }; function Screen() { return ; } const html = renderToString( , ); expect(html).toContain('Confirmar o comprovativo documental.'); expect(html).toContain('Registar resposta'); expect(html).not.toContain('Registar conferência'); expect(html).toContain('id="clarification-7"'); }); test('restricted clarification metadata distinguishes unproven information without exposing evidence', () => { const data: ClarificationData = { ready: true, sources: [], users: [], preservedDecision: true, items: [ { id: 7, application_id: 1, version: 3, status: 'resolved', due_on: '2026-10-30', outcome: 'insufficient', canRespond: false, canReview: false, canReassign: false, }, ], }; function Screen() { return ; } const html = renderToString( , ); expect(html).toContain('Informação permanece por comprovar'); expect(html).toContain('Conteúdo reservado'); expect(html).toContain('conserva a base registada na decisão'); expect(html).not.toContain('