Files
compras/tests/frontend/people-hiring.test.tsx
T
nala c6373365bf
tests / ci (push) Canceled after 0s
commit9
2026-10-30 20:02:30 +02:00

308 lines
11 KiB
TypeScript

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 (
<PeopleOperationalInsights
data={{
method: 'operational_facts_v1',
generated_at: '2026-10-30T12:00:00Z',
coverage: { processes: 2, tasks: 3, approvals: 1 },
overdue: {
items: 2,
processes: 1,
maximum_days: 7,
oldest: [
{
id: 'clarification-7',
reference: 'PES-42',
label: 'Prazo vencido',
due_on: '2026-10-23',
days_overdue: 7,
href: '/pessoas/42#clarification-7',
},
],
},
task_actions: { evaluate: 3 },
tasks_without_deadline: 3,
}}
/>
);
}
const html = renderToString(
<App initialPage={base} initialComponent={Screen} />,
);
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('<form');
});
test('both hiring paths are available in the real creation form', () => {
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(
<App initialPage={page} initialComponent={PeopleIndex} />,
);
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(
<App initialPage={page} initialComponent={PeopleShow} />,
);
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(
<App initialPage={page} initialComponent={PeopleAccess} />,
);
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(
<App initialPage={page} initialComponent={PeopleIndex} />,
);
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 <PeopleClarifications processId={1} data={data} />;
}
const html = renderToString(
<App initialPage={base} initialComponent={Screen} />,
);
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 <PeopleClarifications processId={1} data={data} />;
}
const html = renderToString(
<App initialPage={base} initialComponent={Screen} />,
);
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('<form');
});