Files
Investidor-V2/docs/investmoz/education/examples/package.test.mjs
T
nala 250ac35fd1
tests / ci (push) Canceled after 0s
first commit
2026-09-28 10:01:09 +02:00

113 lines
4.6 KiB
JavaScript

// Verificacao de consistencia documental, nao validacao funcional do portal.
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
const root = new URL('../', import.meta.url);
async function csv(name) {
const text = await readFile(new URL(name, root), 'utf8');
const lines = text.trim().split(/\r?\n/);
const parse = (line) =>
[...line.matchAll(/"((?:[^"]|"")*)"(?:,|$)/g)].map((match) =>
match[1].replaceAll('""', '"'),
);
const header = parse(lines.shift());
return lines.map((line) => {
const cells = parse(line);
assert.equal(cells.length, header.length, name + ': numero de colunas');
return Object.fromEntries(header.map((key, i) => [key, cells[i]]));
});
}
await test('33 requirements retain IDs and resolve entities, rules, risks and acceptance tests', async () => {
const rows = await csv('requirements.csv');
const entities = new Set(
(await csv('entities.csv')).map((e) => e.entidade),
);
const spec = await readFile(new URL('specification.md', root), 'utf8');
assert.equal(rows.length, 33);
assert.equal(new Set(rows.map((r) => r.id)).size, rows.length);
for (const [index, row] of rows.entries()) {
assert.equal(row.id, 'RF-EDU-' + String(index + 1).padStart(3, '0'));
for (const entity of row.dados_entidades.split(';'))
assert.ok(entities.has(entity), entity);
for (const rule of row.regra_negocio.split(';'))
assert.ok(spec.includes(rule), rule);
assert.ok(spec.includes(row.risco), row.risco);
assert.ok(row.criterio_aceitacao.length > 20);
assert.ok(row.endpoint_proposto.startsWith('/api/v1/education/'));
assert.equal(row.estado, 'Proposta');
}
});
await test('entities, RNF, indicators and conformity matrices are complete and explicitly proposed', async () => {
assert.equal((await csv('entities.csv')).length, 44);
assert.equal((await csv('nonfunctional.csv')).length, 18);
const indicators = await csv('indicators.csv');
assert.equal(indicators.length, 25);
for (const indicator of indicators)
assert.match(indicator.meta, /Pendente/);
const conformity = await csv('conformity.csv');
assert.equal(
conformity.filter((r) => r.categoria.startsWith('Módulo ')).length,
20,
);
for (const item of conformity)
assert.ok(
[
'Conforme',
'Parcialmente conforme',
'Não conforme',
'Pendente de validação',
].includes(item.classificacao),
);
});
await test('OpenAPI proposal resolves local refs and guards all modifying operations', async () => {
const api = JSON.parse(
await readFile(new URL('openapi.proposed.json', root), 'utf8'),
);
assert.equal(api.openapi, '3.1.0');
assert.equal(api['x-artifact-status'], 'Proposta');
const operations = new Set();
function walk(value) {
if (!value || typeof value !== 'object') return;
if (value.$ref) {
assert.ok(value.$ref.startsWith('#/'));
let target = api;
for (const part of value.$ref.slice(2).split('/'))
target =
target?.[part.replaceAll('~1', '/').replaceAll('~0', '~')];
assert.ok(target, value.$ref);
}
for (const nested of Object.values(value)) walk(nested);
}
walk(api);
for (const [path, methods] of Object.entries(api.paths)) {
assert.ok(path.startsWith('/api/v1/education/'));
for (const method of ['get', 'post', 'patch']) {
const operation = methods[method];
if (!operation) continue;
assert.ok(!operations.has(operation.operationId));
operations.add(operation.operationId);
assert.ok(operation.responses['401']);
if (method !== 'get')
assert.ok(
operation.parameters.some((p) =>
p.$ref.endsWith('/Idempotency'),
),
);
if (method === 'patch' || path.endsWith('/decisions'))
assert.ok(
operation.parameters.some((p) => p.$ref.endsWith('/Match')),
);
}
}
});
await test('all thirty requested numbered sections exist in order', async () => {
const text = await readFile(new URL('specification.md', root), 'utf8');
const numbers = [...text.matchAll(/^## (\d+)\. /gm)].map((m) =>
Number(m[1]),
);
assert.deepEqual(
numbers,
Array.from({ length: 30 }, (_, i) => i + 1),
);
});