// Synthetic browser check of the actual Results window; no datastore 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'; 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 finding=makeSheet('Synthetic',[['Title','Status','Source Rule ID','Verwandte Daten'], ['Synthetic SMBv1 finding','Matched','S-SMB-v1','synthetic::rule-details-S-SMB-v1']], '', 'synthetic.html').analysis.records[0];finding.importFileId='synthetic'; const own=makeSheet('PingCastle · Details',[['Domain controller'],['DUMMY-DC']], '', 'synthetic.html',{id:'pingcastle-section-synthetic::rule-details-S-SMB-v1'}); const inventory=makeSheet('PingCastle · Inventory',[['Domain controller','SMB v1'],['DUMMY-OTHER','NO']], '', 'synthetic.html'); const root=createRoot(document.getElementById('root')); window.renderSynthetic=tool=>root.render({}} onClose={()=>{}}/>); window.renderSynthetic('pingcastle');` }, 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??'
');}); await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve));let browser; try { browser=await chromium.launch({headless:true,channel:'chrome'});const page=await browser.newPage({viewport:{width:1280,height:900}}); page.on('pageerror', error=>console.error(error.message)); await page.goto('http://127.0.0.1:'+server.address().port+'/'); for(const theme of ['dark','light'])for(const tool of ['pingcastle','maester']) { await page.evaluate(({theme,tool})=>{document.documentElement.dataset.theme=theme;window.renderSynthetic(tool);},{theme,tool}); try { await page.waitForFunction(tool=>document.querySelector('.rich-text-table-row--violation')?.textContent?.includes(tool==='pingcastle'?'DUMMY-DC':'DUMMY-BAD'),tool,{timeout:5000}); } catch(error) { console.error(tool, await page.locator('tbody tr').evaluateAll(rows=>rows.map(row=>({text:row.textContent,cls:row.className})))); throw error; } const red=await page.locator('.rich-text-table-row--violation td').first().evaluate(cell=>({actual:getComputedStyle(cell).backgroundColor, token:getComputedStyle(document.documentElement).getPropertyValue('--violation-highlight-bg').trim(),text:cell.textContent})); const tokenColor=await page.evaluate(token=>{const element=document.createElement('span');element.style.backgroundColor=token;document.body.append(element);const result=getComputedStyle(element).backgroundColor;element.remove();return result;},red.token); assert.equal(red.actual,tokenColor); const neutral=await page.locator('tbody tr').filter({hasText:tool==='pingcastle'?'DUMMY-OTHER':'DUMMY-UNKNOWN'}).first().evaluate(row=>row.classList.contains('rich-text-table-row--violation')); assert.equal(neutral,false); if(tool==='maester')assert.equal(await page.locator('.rich-text-table-row--match').count(),1); } console.log('Actual Results window: red affected evidence, neutral inventory/unknown rows and explicit pass rows verified in both themes.'); } finally {await browser?.close();await new Promise(resolve=>server.close(resolve));}