128 lines
3.9 KiB
JavaScript
128 lines
3.9 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {
|
|
publicBusinessOfflineHtml,
|
|
downloadPublicBusinessOffline,
|
|
} from '../../resources/js/lib/public-business-offline.ts';
|
|
|
|
const savedAt = new Date('2026-11-02T15:00:00.000Z');
|
|
const record = {
|
|
slug: 'synthetic',
|
|
title: 'Negócio sintético',
|
|
modality: 'company_sale',
|
|
amount_min: '9007199254740993.25',
|
|
currency: 'MZN',
|
|
province: 'Província sintética',
|
|
payload: { private: 'RESERVED' },
|
|
owner_user_id: 73,
|
|
};
|
|
|
|
await test('offline fiche is self-contained, preserves exact public values and identifies capture versus publication', () => {
|
|
const html = publicBusinessOfflineHtml(
|
|
record,
|
|
'Venda da empresa',
|
|
'https://portal.example.invalid',
|
|
savedAt,
|
|
);
|
|
assert.match(html, /9007199254740993\.25 MZN/);
|
|
assert.match(html, /2026-11-02T15:00:00\.000Z/);
|
|
assert.match(html, /Publicação no portal<\/dt><dd>Não indicado/);
|
|
assert.match(html, /Província sintética/);
|
|
assert.match(
|
|
html,
|
|
/href="https:\/\/portal\.example\.invalid\/negocios\/synthetic"/,
|
|
);
|
|
assert.doesNotMatch(
|
|
html,
|
|
/RESERVED|owner_user_id|<script|<link|<img|<iframe|<form|src=/,
|
|
);
|
|
assert.match(html, /default-src 'none'/);
|
|
assert.match(html, /<html lang="pt-MZ">/);
|
|
});
|
|
|
|
await test('untrusted text and slugs cannot create executable markup or an external source link', () => {
|
|
const html = publicBusinessOfflineHtml(
|
|
{
|
|
...record,
|
|
slug: '//external.invalid/"',
|
|
title: '<script>alert(1)</script>',
|
|
objective: '<img src=x onerror=alert(1)> & "value"',
|
|
},
|
|
'"malicious"',
|
|
'https://portal.example.invalid',
|
|
savedAt,
|
|
);
|
|
assert.doesNotMatch(html, /<script|<img/);
|
|
assert.match(html, /<script>/);
|
|
assert.match(
|
|
html,
|
|
/<img src=x onerror=alert\(1\)> & "value"/,
|
|
);
|
|
assert.match(
|
|
html,
|
|
/href="https:\/\/portal\.example\.invalid\/negocios\/%2F%2Fexternal/,
|
|
);
|
|
assert.throws(
|
|
() =>
|
|
publicBusinessOfflineHtml(
|
|
record,
|
|
'Venda',
|
|
'javascript:alert(1)',
|
|
savedAt,
|
|
),
|
|
/inválida/,
|
|
);
|
|
});
|
|
|
|
await test('download creates a standalone HTML file and releases its temporary URL', () => {
|
|
const previousWindow = globalThis.window,
|
|
previousDocument = globalThis.document;
|
|
const previousCreate = URL.createObjectURL.bind(URL),
|
|
previousRevoke = URL.revokeObjectURL.bind(URL);
|
|
let clicked = false,
|
|
removed = false,
|
|
revoked,
|
|
blob,
|
|
release;
|
|
const link = {
|
|
click() {
|
|
clicked = true;
|
|
},
|
|
remove() {
|
|
removed = true;
|
|
},
|
|
};
|
|
try {
|
|
globalThis.window = {
|
|
location: { origin: 'https://portal.example.invalid' },
|
|
setTimeout(fn) {
|
|
release = fn;
|
|
},
|
|
};
|
|
globalThis.document = {
|
|
createElement: () => link,
|
|
body: { appendChild() {} },
|
|
};
|
|
URL.createObjectURL = (value) => {
|
|
blob = value;
|
|
return 'blob:synthetic';
|
|
};
|
|
URL.revokeObjectURL = (value) => {
|
|
revoked = value;
|
|
};
|
|
downloadPublicBusinessOffline(record, 'Venda da empresa');
|
|
assert.equal(clicked, true);
|
|
assert.equal(removed, true);
|
|
assert.equal(link.download, 'negocio-synthetic.html');
|
|
assert.equal(blob.type, 'text/html;charset=utf-8');
|
|
assert.equal(revoked, undefined);
|
|
release();
|
|
assert.equal(revoked, 'blob:synthetic');
|
|
} finally {
|
|
globalThis.window = previousWindow;
|
|
globalThis.document = previousDocument;
|
|
URL.createObjectURL = previousCreate;
|
|
URL.revokeObjectURL = previousRevoke;
|
|
}
|
|
});
|