165 lines
5.1 KiB
JavaScript
165 lines
5.1 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import { createRequire } from 'node:module';
|
|
import { compileFunction } from 'node:vm';
|
|
import ts from 'typescript';
|
|
import React from 'react';
|
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
const require = createRequire(import.meta.url),
|
|
Empty = () => null;
|
|
const mocks = {
|
|
react: React,
|
|
'@inertiajs/react': {
|
|
Link: ({ href, children }) =>
|
|
React.createElement('a', { href }, children),
|
|
router: {},
|
|
useForm: (data) => ({
|
|
data,
|
|
errors: {},
|
|
processing: false,
|
|
isDirty: false,
|
|
}),
|
|
},
|
|
'@/lib/portal-api': {
|
|
newSubmissionKey: () => '00000000-0000-4000-8000-000000000001',
|
|
},
|
|
'@/components/education-submitted-snapshot': { default: Empty },
|
|
'@/components/investment-territory': { TerritoryFields: Empty },
|
|
'../management/shared': {
|
|
Management: ({ children }) =>
|
|
React.createElement('main', null, children),
|
|
Field: ({ label, children }) =>
|
|
React.createElement('label', null, label, children),
|
|
Pagination: Empty,
|
|
control: '',
|
|
button: '',
|
|
},
|
|
};
|
|
const output = ts.transpileModule(
|
|
fs.readFileSync(
|
|
new URL(
|
|
'../../resources/js/pages/education/index.tsx',
|
|
import.meta.url,
|
|
),
|
|
'utf8',
|
|
),
|
|
{
|
|
compilerOptions: {
|
|
module: ts.ModuleKind.CommonJS,
|
|
target: ts.ScriptTarget.ES2022,
|
|
jsx: ts.JsxEmit.ReactJSX,
|
|
},
|
|
},
|
|
).outputText;
|
|
const module = { exports: {} };
|
|
compileFunction(output, ['require', 'module', 'exports'])(
|
|
(name) => mocks[name] ?? require(name),
|
|
module,
|
|
module.exports,
|
|
);
|
|
const Index = module.exports.default;
|
|
const counts = {
|
|
total: 3,
|
|
submitted: 1,
|
|
reviewed: 1,
|
|
rejected: 0,
|
|
expired: 1,
|
|
to_review: 2,
|
|
};
|
|
const group = (data) => ({
|
|
data,
|
|
total: data.length,
|
|
current_page: 1,
|
|
last_page: 1,
|
|
links: [],
|
|
});
|
|
const base = {
|
|
today: '2026-11-03',
|
|
territories: [],
|
|
projects: [],
|
|
providers: [],
|
|
courses: [],
|
|
occupations: [],
|
|
skills: [],
|
|
draftsAvailable: false,
|
|
ownDrafts: null,
|
|
filters: { scope: 'all' },
|
|
workQueue: {
|
|
actor_id: 1,
|
|
drafts: 1,
|
|
demands: counts,
|
|
capacities: { ...counts, total: 1, submitted: 0, to_review: 4 },
|
|
},
|
|
indicators: {
|
|
demand_records: 42,
|
|
capacity_records: 17,
|
|
pending_demands: 9,
|
|
expired_demands: 4,
|
|
},
|
|
demands: group([
|
|
{
|
|
id: 'one',
|
|
qualification: 'SYNTHETIC qualification',
|
|
quantity: 1000,
|
|
status: 'submitted',
|
|
version_no: 1,
|
|
valid_until: '2027-12-31',
|
|
period_start: '2027-01-01',
|
|
period_end: '2027-06-30',
|
|
source: 'SYNTHETIC source',
|
|
can_review: false,
|
|
review_unavailable: 'self',
|
|
details_url: '/management/education/demands/one?scope=mine',
|
|
},
|
|
]),
|
|
capacities: group([]),
|
|
};
|
|
const render = (patch) =>
|
|
renderToStaticMarkup(React.createElement(Index, { ...base, ...patch }));
|
|
test('personal record counts coexist with the unchanged global indicators and retain separate categories', () => {
|
|
const html = render();
|
|
assert.match(html, /O meu acompanhamento/);
|
|
assert.match(html, /Declarações de procura:.*?<strong>42/s);
|
|
assert.match(html, /Submetidas por mim: 3/);
|
|
assert.match(html, /Submetidas por mim: 1/);
|
|
assert.doesNotMatch(html, /Submetidas por mim: 1000/);
|
|
assert.match(html, /Disponíveis para a minha revisão independente: 2/);
|
|
assert.match(html, /Disponíveis para a minha revisão independente: 4/);
|
|
});
|
|
test('a declaration links to its detailed context and the list no longer asks for repeated review forms', () => {
|
|
const html = render();
|
|
assert.ok(
|
|
html.includes('href="/management/education/demands/one?scope=mine"'),
|
|
);
|
|
assert.match(html, /Consultar declaração/);
|
|
assert.match(html, /a revisão cabe a outro gestor/);
|
|
assert.doesNotMatch(
|
|
html,
|
|
/Guardar decisão|Justificação e evidência da revisão/,
|
|
);
|
|
});
|
|
test('the independent review scope hides an inapplicable status question and preserves the normal filters', () => {
|
|
const html = render({
|
|
filters: { scope: 'review', q: 'SYNTHETIC', status: '' },
|
|
});
|
|
assert.match(html, /value="review" selected/);
|
|
assert.doesNotMatch(html, /<label>Estado/);
|
|
assert.match(html, /Qualificação/);
|
|
assert.match(html, /SYNTHETIC/);
|
|
assert.match(render({ filters: { scope: 'mine' } }), /<label>Estado/);
|
|
});
|
|
test('an unavailable draft count is not presented as zero and declaration text is escaped', () => {
|
|
const html = render({
|
|
workQueue: { ...base.workQueue, drafts: null },
|
|
demands: group([
|
|
{
|
|
...base.demands.data[0],
|
|
qualification: '<img src=x onerror=alert(1)>',
|
|
},
|
|
]),
|
|
});
|
|
assert.doesNotMatch(html, /Rascunhos privados por concluir: 0|<img/);
|
|
assert.ok(html.includes('<img'));
|
|
});
|