researchbee / tests /test_frontend_re3data.cjs
nikeshn's picture
Upload 14 files
7936dbe verified
Raw History Blame Contribute Delete
4.44 kB
/* Node-only behavioral checks for the v1.8.3 frontend additions:
re3data supplementary list and nearest-subject disclosure styling.
Runs the actual embedded functions; not a substitute for a browser test. */
const fs = require('node:fs'), vm = require('node:vm'), assert = require('node:assert/strict'), path = require('node:path');
const html = fs.readFileSync(path.join(__dirname, '../ResearchBee_LibGuides.html'), 'utf8');
function segment(start, end) {
const i = html.indexOf(start);
assert.ok(i >= 0, `missing ${start}`);
return html.slice(i, html.indexOf(end, i));
}
const context = { console, URL, encodeURIComponent, rbText: x => x };
vm.createContext(context);
vm.runInContext(
segment('function safeHttpsUrl(', 'function makeExternalLink(') +
segment('function esc(str)', '// Evidence-backed links') +
segment('function rbTrustedAnchor(', 'function rbJournalTitle(') +
segment('function rbRe3dataSearchUrl(', 'function renderRepoResults('),
context);
let count = 0;
const check = fn => { fn(); count++; };
const render = sup => vm.runInContext(`rbRenderRe3dataSupplement(${JSON.stringify(sup)})`, context);
const ok = {
status: 'ok', query: 'materials science', recommended_view: 'collapsed',
message: '1 additional repository from re3data.org matched "materials science".',
repositories: [{
id: 'r3d100012345', name: 'Materials <b>Data</b> Facility', url: 'https://materialsdatafacility.org/',
re3data_url: 'https://www.re3data.org/repository/r3d100012345', description: 'desc <script>x</script>',
subjects: ['Materials Science'], persistent_identifier: 'DOI', data_upload: 'open', data_access: 'open',
versioning: 'Yes', certificates: [], countries: ['USA'],
review_notes: ['Listed in re3data.org; not reviewed by KU Library.'], source_note: 'Details as recorded by re3data.org.',
}],
};
check(() => { const out = render(ok); assert.ok(out.includes('<details class="rb-re3data">')); assert.ok(!out.includes(' open>')); });
check(() => assert.ok(render({ ...ok, recommended_view: 'expanded' }).includes('<details class="rb-re3data" open>')));
check(() => { const out = render(ok); assert.ok(!out.includes('<script>')); assert.ok(!out.includes('<b>Data')); assert.ok(out.includes('&lt;b&gt;')); });
check(() => assert.ok(render(ok).includes('href="https://www.re3data.org/repository/r3d100012345"')));
check(() => assert.ok(render(ok).includes('Not reviewed by KU Library')));
check(() => assert.ok(render(ok).includes('search?query=materials%20science')));
// Unsafe URLs never become links.
check(() => {
const bad = { ...ok, repositories: [{ ...ok.repositories[0], url: 'javascript:alert(1)', re3data_url: 'https://evil.example.org/x' }] };
const out = render(bad);
assert.ok(!out.includes('javascript:'));
assert.ok(!out.includes('evil.example.org'));
});
check(() => assert.equal(render(null), ''));
check(() => assert.equal(render({ status: 'disabled' }), ''));
check(() => assert.equal(render({ status: 'skipped' }), ''));
check(() => { const out = render({ status: 'unavailable', query: 'x', message: 're3data.org could not be reached.' }); assert.ok(out.includes('could not be reached')); assert.ok(out.includes('Search re3data.org yourself')); });
check(() => assert.ok(render({ status: 'ok', repositories: [] }).includes('No additional re3data repositories')));
// Nearest-subject disclosure uses the highlighted note style.
const understanding = segment('function rbV18RenderUnderstanding(', 'function rbV18RenderNoResults(');
vm.runInContext(understanding.replace(/^function rbV18RenderUnderstanding/, 'function rbV18RenderUnderstanding') + '', context);
// renderManuscriptUnderstanding is only used in manuscript mode.
const subj = mapping => vm.runInContext(`rbV18RenderUnderstanding(${JSON.stringify({ user_message: 'm', subject_understanding: {}, subject_mapping: mapping })}, "subject")`, context);
check(() => assert.ok(subj({ used_nearest_category: true, alternatives: [] }).includes('rb-subject-map-note nearest')));
check(() => assert.ok(subj({ match_type: 'synonym', alternatives: [] }).includes('rb-subject-map-note nearest')));
check(() => assert.ok(subj({ spelling_corrected: true, used_nearest_category: true }).includes('rb-subject-map-note spelling')));
check(() => assert.ok(subj({ match_type: 'exact' }).includes('class="rb-subject-map-note"')));
console.log(`${count} re3data/subject frontend checks passed (Node VM; no browser).`);