Assessor_2.0/outputs/dummy-work-export-verificat...

72 lines
4.7 KiB
JavaScript

import assert from 'node:assert/strict';
export async function verify(vite, dataset, sheet) {
const exports = await vite.ssrLoadModule('/src/exports/work-view-export.ts');
const { genericProfile } = await vite.ssrLoadModule('/src/profiles/generic/generic-profile.ts');
const { filterAndSortRecords } = await vite.ssrLoadModule('/src/features/search-filter/filter-records.ts');
const { recordResultSheets } = await vite.ssrLoadModule('/src/features/linked-results/record-results.ts');
const { resultSectionsFor } = await vite.ssrLoadModule('/src/features/linked-results/result-message.ts');
const { toolIdForRecord } = await vite.ssrLoadModule('/src/importers/status-normalization.ts');
const options = { dataset, activeProfile: genericProfile, search: '', statusFilter: 'deviation', facetFilters: {},
sortColumn: 'all', sortDirection: 'asc', actionOnly: false, reviews: {} };
const counts = [];
for (const statusFilter of ['deviation', 'all']) {
const records = filterAndSortRecords(sheet, { ...options, statusFilter });
const report = exports.buildWorkViewExport({ dataset, sheet, records, generatedAt: new Date().toISOString() });
assert.deepEqual(report.entries.map(entry => entry.id), records.map(record => record.id));
let cells = 0;
let sources = 0;
let sections = 0;
for (const [index, record] of records.entries()) {
const entry = report.entries[index];
const tool = toolIdForRecord(record, sheet.toolId ?? dataset.profileId);
const linked = recordResultSheets(record, dataset.sheets, sheet.id, tool);
assert.deepEqual(entry.resultSheetIds, linked.map(item => item.id));
assert.equal(entry.resultRowCount, linked.reduce((sum, item) => sum + item.analysis.records.length, 0));
const actual = entry.observed.map(block => block.value).join('\n');
for (const item of linked) for (const row of item.analysis.records) for (const field of row.fields) {
assert.ok(actual.includes(`${field.label}: ${field.value}`), 'Lost result cell');
cells++;
}
for (const section of resultSectionsFor(record, tool)) {
assert.ok(entry.observed.some(block => block.value === section.value), 'Lost result section');
sections++;
}
for (const source of record.policySourceEvidence ?? []) {
assert.ok(actual.includes(source.id), 'Lost GPO observation');
assert.ok(actual.includes(source.sourceReference), 'Lost GPO evidence path');
sources++;
}
}
const csv = exports.renderWorkViewCsv(report);
const html = exports.renderWorkViewHtml(report);
const md = exports.renderWorkViewMarkdown(report);
const { read, utils } = await import('xlsx');
// Decode the UTF-8 BOM before passing a JS string to SheetJS (Excel handles it).
const book = read(csv.replace(/^\ufeff/, ''), { type: 'string', raw: true, FS: ';' });
const rows = utils.sheet_to_json(book.Sheets[book.SheetNames[0]], { header: 1, raw: true });
const expectedCsvRows = exports.workViewCsvRows(report);
assert.equal(rows.length, expectedCsvRows.length, 'CSV row count');
const differences = [];
rows.forEach((row, index) => row.forEach((cell, col) => {
const expected = expectedCsvRows[index][col];
if (cell !== expected) {
let first = 0;
while (first < Math.min(cell.length, expected.length) && cell[first] === expected[first]) first++;
differences.push({ row: index, column: col, actualLength: cell.length, expectedLength: expected.length,
firstDifference: first, actualChar: cell.charCodeAt(first), expectedChar: expected.charCodeAt(first) });
}
}));
if (differences.length) { console.log(JSON.stringify({ csvDifferences: differences.slice(0, 5) })); throw new Error('CSV content round-trip differs'); }
assert.ok(rows.every(row => row.length === 2), 'Not exactly two CSV columns');
assert.equal((html.match(/<article class="finding">/g) ?? []).length, records.length);
assert.equal((md.match(/^\| /gm) ?? []).length, records.length + 2);
counts.push({ statusFilter, records: records.length, csvContinuationRows: rows.length - records.length - 1, resultRows: report.entries.reduce((sum, item) => sum + item.resultRowCount, 0),
checkedResultCells: cells, resultSections: sections, gpoObservations: sources,
missingResultWarnings: report.entries.filter(item => item.observed.some(block => /nicht geladen/.test(block.value))).length,
oversizedCsvCells: rows.flat().filter(cell => String(cell).length > 32767).length,
bytes: { csv: Buffer.byteLength(csv), html: Buffer.byteLength(html), md: Buffer.byteLength(md) } });
}
console.log(JSON.stringify({ verification: 'passed', counts }, null, 2));
}