Assessor_2.0/tests/results-excel-browser-check...

60 lines
6.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Actual browser downloads from synthetic Results; no datastore access or mutation.
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import { createServer } from 'node:http';
import { pathToFileURL } from 'node:url';
import { build } from 'esbuild';
import { read, utils } from 'xlsx';
const { chromium } = await import(pathToFileURL(process.env.PLAYWRIGHT_MODULE).href);
const main = await readFile('src/main.tsx', 'utf8');
const styles = [...main.matchAll(/^import '([^']+\.css)';/gm)].map(([, path]) => `import ${JSON.stringify(path.startsWith('.') ? './src/' + path.slice(2) : path)};`).join('\n');
const bundle = await build({ stdin: { resolveDir: process.cwd(), loader: 'tsx', contents: `${styles}
import React from 'react';import {createRoot} from 'react-dom/client';
import {FloatingResultsWindow} from './src/features/linked-results/FloatingResultsWindow';
import {makeSheet} from './src/importers/sheet-factory';
const rows=Array.from({length:1001},(_,i)=>['OBJECT-'+(i+1),'000'+i]);
const sheet=makeSheet('Synthetic linked',[['Object','Value'],...rows],'','synthetic.xlsx');
const finding=makeSheet('Synthetic indicator',[['Name','Description','Result Message','Number of Results','Likelihood of Compromise'],['Complete synthetic evidence','Original certificate description','Found 17 affected templates','17','Original impact explanation']],'','synthetic.csv').analysis.records[0];
const root=createRoot(document.getElementById('root'));
root.render(<FloatingResultsWindow id="synthetic" title="Results – Complete synthetic evidence" sheets={[sheet]} finding={finding} toolId="purple-knight" outcome="fail"
sections={[{title:'Source result',value:'Complete prose\\n\\n| Object | Status |\\n| --- | --- |\\n'+rows.map(([name])=>'| '+name+' | Failed |').join('\\n')},
{title:'Native HTML evidence',value:'<table><thead><tr><th>Object</th></tr></thead><tbody>'+rows.map(([name])=>'<tr><td>'+name+'</td></tr>').join('')+'</tbody></table>'}]}
color="" zIndex={1} offset={0} search="OBJECT-1001" onActivate={()=>{}} onClose={()=>{}} onToggleBookmark={()=>{}}/>);` }, jsx:'automatic',bundle:true,write:false,outdir:'synthetic',format:'iife',loader:{'.woff2':'dataurl','.woff':'dataurl','.png':'dataurl','.svg':'dataurl'} });
const server=createServer((req,res)=>{const file=bundle.outputFiles.find(file=>req.url==='/'+file.path.split(/[\\/]/).at(-1));res.setHeader('Content-Type',file?(req.url.endsWith('.css')?'text/css':'text/javascript'):'text/html');res.end(file?.contents??'<!doctype html><html><head><meta charset="utf-8"><link rel="stylesheet" href="/stdin.css"></head><body><div id="root"></div><script src="/stdin.js"></script></body></html>');});
await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve));let browser;
async function workbook(download) {const stream=await download.createReadStream();const chunks=[];for await(const chunk of stream)chunks.push(chunk);return read(Buffer.concat(chunks),{type:'buffer'});}
try {
browser=await chromium.launch({headless:true,channel:'chrome'});
const page=await browser.newPage({viewport:{width:1280,height:900}});
const errors=[];page.on('pageerror',error=>errors.push(error.message));
await page.goto('http://127.0.0.1:'+server.address().port+'/');
await page.waitForSelector('table');
const all=page.getByRole('button',{name:'Export entire Results to Excel',exact:true});
const selected=page.getByRole('button',{name:'Export selected tables to Excel',exact:true});
for(const theme of ['dark','light']) {
await page.evaluate(theme=>document.documentElement.dataset.theme=theme,theme);
assert.deepEqual(await page.locator('table').evaluateAll(tables=>tables.map(table=>table.tBodies[0].rows.length)),[1001,1001,1001]);
assert.equal(await all.isEnabled(),true);assert.equal(await selected.isEnabled(),false);
const grey=await selected.evaluate(button=>getComputedStyle(button).color);
const entire=page.waitForEvent('download');await all.click();const full=await workbook(await entire);
const tableNames=full.SheetNames.filter(name=>/^Results(?: \d+)?$/.test(name));assert.equal(tableNames.length,3);
assert.deepEqual(full.SheetNames.slice(0,3),tableNames);
assert.match(full.Sheets[tableNames[0]].A1.v,/Complete synthetic evidence/);
for(const name of tableNames){const rows=utils.sheet_to_json(full.Sheets[name],{header:1});assert.equal(rows.length,name==='Results'?1006:1003);assert.equal(rows[1002][0],'OBJECT-1001');}
assert.match(full.Sheets.Results.A1006.v,/Complete prose/);assert.equal(full.SheetNames.includes('Results text'),false);
for(const name of full.SheetNames)assert.match(full.Sheets[name].A1.v,/Complete synthetic evidence/);
assert.equal(full.Sheets['Finding context'].C3.v,'Original certificate description');
assert.equal(full.Sheets['Finding context'].C5.v,'17');
await page.getByRole('checkbox',{name:'Select table for Excel export'}).nth(1).check();
assert.equal(await selected.isEnabled(),true);
const colors=await page.locator('.results-window-export').evaluateAll(buttons=>buttons.map(button=>getComputedStyle(button).color));
assert.notEqual(colors[0],colors[1]);assert.notEqual(colors[1],grey);
const subsetDownload=page.waitForEvent('download');await selected.click();const subset=await workbook(await subsetDownload);
assert.equal(subset.SheetNames.length,3);assert.equal(subset.SheetNames[0],'Results');assert.equal(subset.SheetNames[1],'Finding context');assert.equal(subset.SheetNames[2],'Export info');assert.equal(subset.Sheets[subset.SheetNames[0]].A1003.v,'OBJECT-1001');
assert.deepEqual(utils.sheet_to_json(subset.Sheets['Finding context'],{header:1}),utils.sheet_to_json(full.Sheets['Finding context'],{header:1}));
await page.getByRole('checkbox',{name:'Select table for Excel export'}).nth(1).uncheck();assert.equal(await selected.isEnabled(),false);
}
assert.deepEqual(errors,[]);
console.log('Both themes: all 1001 rows shown and downloaded, entire Results text included, selective export exact, distinct icon colors and disabled state verified.');
} finally {await browser?.close();await new Promise(resolve=>server.close(resolve));}