272 lines
9.2 KiB
JavaScript
272 lines
9.2 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import { createRequire } from 'node:module';
|
|
import React from 'react';
|
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
import ts from 'typescript';
|
|
|
|
const require = createRequire(import.meta.url);
|
|
const source = fs.readFileSync(
|
|
new URL(
|
|
'../../resources/js/pages/management/editorial-edition.tsx',
|
|
import.meta.url,
|
|
),
|
|
'utf8',
|
|
);
|
|
const code = ts.transpileModule(source, {
|
|
compilerOptions: {
|
|
module: ts.ModuleKind.CommonJS,
|
|
target: ts.ScriptTarget.ES2022,
|
|
jsx: ts.JsxEmit.ReactJSX,
|
|
},
|
|
}).outputText;
|
|
const module = { exports: {} };
|
|
new Function('require', 'module', 'exports', code)(
|
|
(name) => {
|
|
if (name === '../portfolio/shared')
|
|
return { labels: { description: 'Visão e proposta de valor' } };
|
|
if (name === '@inertiajs/react')
|
|
return {
|
|
Link: ({ href, children, ...rest }) =>
|
|
React.createElement('a', { href, ...rest }, children),
|
|
useForm: (data) => ({
|
|
data,
|
|
errors: {},
|
|
processing: false,
|
|
setData() {},
|
|
transform() {},
|
|
post() {},
|
|
}),
|
|
};
|
|
if (name === './shared')
|
|
return {
|
|
Management: ({ children }) =>
|
|
React.createElement('main', null, children),
|
|
Field: ({ label, children }) =>
|
|
React.createElement('label', null, label, children),
|
|
control: '',
|
|
button: '',
|
|
};
|
|
if (name === './editorial-workflow')
|
|
return {
|
|
states: {
|
|
draft: 'Rascunho',
|
|
approved: 'Aprovado',
|
|
in_review: 'Em revisão',
|
|
},
|
|
};
|
|
return require(name);
|
|
},
|
|
module,
|
|
module.exports,
|
|
);
|
|
const Page = module.exports.default;
|
|
const props = {
|
|
resource: {
|
|
id: 91,
|
|
title: 'Artigo QA',
|
|
published: true,
|
|
public_edition_no: 1,
|
|
},
|
|
manager: true,
|
|
legalReviewer: true,
|
|
current: true,
|
|
canApprove: true,
|
|
independentRequired: true,
|
|
history: [],
|
|
editions: [{ id: 'qa-edition', revision_no: 2, state: 'draft' }],
|
|
reviewers: [{ id: 5, name: 'Equipa de revisão' }],
|
|
edition: {
|
|
id: 'qa-edition',
|
|
revision_no: 2,
|
|
version: 1,
|
|
state: 'draft',
|
|
content_hash: 'a'.repeat(64),
|
|
fresh: true,
|
|
legal_required: false,
|
|
approval: null,
|
|
legal_validation: null,
|
|
payload: {
|
|
resource: {
|
|
title: 'Novo título',
|
|
editorial_content: JSON.stringify({
|
|
body: '<script>não executar</script>',
|
|
}),
|
|
},
|
|
files: [
|
|
{
|
|
id: 'qa-file',
|
|
file_name: 'anexo.pdf',
|
|
version_no: 2,
|
|
sha256: 'b'.repeat(64),
|
|
},
|
|
],
|
|
},
|
|
},
|
|
};
|
|
const render = (changes = {}) =>
|
|
renderToStaticMarkup(React.createElement(Page, { ...props, ...changes }));
|
|
|
|
test('draft preserves public version and offers submission without approval or publication', () => {
|
|
const html = render();
|
|
assert.match(html, /Versão pública: edição 1/);
|
|
assert.match(html, /value="submit"/);
|
|
assert.doesNotMatch(html, /value="(?:approve|publish)"/);
|
|
assert.match(
|
|
html,
|
|
/href="\/management\/editorial\/resources\/91\/editions\/qa-edition\/files\/qa-file" target="_blank" rel="noopener noreferrer"/,
|
|
);
|
|
assert.match(html, /<script>/);
|
|
assert.doesNotMatch(html, /<script>/);
|
|
});
|
|
test('approved edition offers explicit publication; stale files and historical versions cannot be published', () => {
|
|
assert.match(
|
|
render({
|
|
edition: { ...props.edition, state: 'approved', approval: '{}' },
|
|
}),
|
|
/value="publish"/,
|
|
);
|
|
const stale = render({
|
|
edition: { ...props.edition, state: 'approved', fresh: false },
|
|
});
|
|
assert.match(stale, /Os anexos mudaram/);
|
|
assert.doesNotMatch(stale, /value="publish"/);
|
|
const staleReview = render({
|
|
edition: { ...props.edition, state: 'in_review', fresh: false },
|
|
});
|
|
assert.match(staleReview, /value="return"/);
|
|
assert.doesNotMatch(staleReview, /value="approve"/);
|
|
const historical = render({ current: false });
|
|
assert.match(historical, /Versão histórica para consulta/);
|
|
assert.doesNotMatch(historical, /<form/);
|
|
assert.match(historical, /edition=qa-edition/);
|
|
});
|
|
test('contributor does not see independent approval or legal-validation actions', () => {
|
|
const html = render({
|
|
canApprove: false,
|
|
edition: { ...props.edition, state: 'in_review' },
|
|
});
|
|
assert.doesNotMatch(html, /value="(?:approve|legal_validate)"/);
|
|
assert.match(html, /responsável independente/);
|
|
});
|
|
|
|
test('portfolio edition reuses review screen with its own context, history and edit routes', () => {
|
|
const html = render({
|
|
subject: 'portfolio',
|
|
resource: { ...props.resource, id: 'qa-dossier' },
|
|
edition: {
|
|
...props.edition,
|
|
payload: {
|
|
...props.edition.payload,
|
|
resource: {
|
|
title: 'Ficha privada',
|
|
source: 'Fonte QA',
|
|
content: { description: '<script>não executar</script>' },
|
|
},
|
|
files: [],
|
|
links: [
|
|
{
|
|
target_type: 'projects',
|
|
target_key: 'qa-project',
|
|
context: { name: 'Projecto QA', code: 'QA-1' },
|
|
},
|
|
],
|
|
},
|
|
},
|
|
});
|
|
assert.match(html, /href="\/management\/portfolio\/qa-dossier"/);
|
|
assert.match(
|
|
html,
|
|
/\/management\/editorial\/portfolio\/qa-dossier\?edition=qa-edition/,
|
|
);
|
|
assert.match(html, /Visão e proposta de valor/);
|
|
assert.match(html, /Contexto: Projecto QA/);
|
|
assert.doesNotMatch(html, /Alterar artigo|Alterar metadados\/documento/);
|
|
assert.match(html, /<script>/);
|
|
});
|
|
|
|
test('portfolio contributor cannot select publication of an approved edition', () => {
|
|
assert.doesNotMatch(
|
|
render({
|
|
subject: 'portfolio',
|
|
canApprove: false,
|
|
edition: { ...props.edition, state: 'approved' },
|
|
}),
|
|
/value="publish"/,
|
|
);
|
|
assert.match(
|
|
render({
|
|
subject: 'portfolio',
|
|
canApprove: true,
|
|
edition: { ...props.edition, state: 'approved' },
|
|
}),
|
|
/value="publish"/,
|
|
);
|
|
});
|
|
|
|
test('portfolio review presents proposed base data and territory without applying them', () => {
|
|
const html = render({
|
|
subject: 'portfolio',
|
|
edition: {
|
|
...props.edition,
|
|
payload: {
|
|
...props.edition.payload,
|
|
resource: {
|
|
title: 'Ficha existente',
|
|
_structure: {
|
|
fields: {
|
|
name: 'Nome proposto',
|
|
budget_amount: '999999999999999999.99',
|
|
primary_territory_id: 'qa-district',
|
|
territory_version: 1,
|
|
},
|
|
territory_context: [
|
|
{ id: 'qa-district', name: 'Distrito sintético' },
|
|
],
|
|
},
|
|
},
|
|
files: [],
|
|
},
|
|
},
|
|
});
|
|
assert.match(html, /Alterações propostas nos dados-base/);
|
|
assert.match(html, /Nome proposto/);
|
|
assert.match(html, /999999999999999999.99/);
|
|
assert.match(html, /Localização proposta: Distrito sintético/);
|
|
assert.doesNotMatch(html, /qa-district|territory_version/);
|
|
});
|
|
|
|
test('demographic edition presents provenance, warnings and protected original with a separate publication step', () => {
|
|
const html = render({
|
|
subject: 'demography',
|
|
resource: { ...props.resource, id: 'qa-batch', published: false },
|
|
edition: {
|
|
...props.edition,
|
|
state: 'approved',
|
|
payload: {
|
|
...props.edition.payload,
|
|
resource: {
|
|
title: 'Exemplar sintético',
|
|
source: 'Fonte QA',
|
|
publication_version: 'Edição não indicada no original',
|
|
observations: 10,
|
|
sha256: 'a'.repeat(64),
|
|
dataset_hash: 'b'.repeat(64),
|
|
report: { issue_counts: { unit_not_supplied: 2 } },
|
|
},
|
|
files: [],
|
|
},
|
|
},
|
|
});
|
|
assert.match(html, /10 observações conferidas/);
|
|
assert.match(html, /Edição não indicada no original/);
|
|
assert.match(html, /unit_not_supplied: 2 advertências conservadas/);
|
|
assert.match(
|
|
html,
|
|
/href="\/management\/editorial\/demography\/qa-batch\/original"/,
|
|
);
|
|
assert.match(html, /value="publish"/);
|
|
assert.doesNotMatch(html, /Alterar artigo|Alterar ficha da carteira/);
|
|
});
|