// Synthetic-only geometry acceptance. PLAYWRIGHT_MODULE points to installed Playwright. 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: { contents: `${styles} import React from 'react'; import { createRoot } from 'react-dom/client'; import { FindingReader } from './src/features/finding-reader/FindingReader'; import { makeSheet } from './src/importers/sheet-factory'; const record = makeSheet('Synthetic', [['Name','Result','Description','ShortName','MITRE ATT&CK','MITRE D3FEND'], ['Synthetic LDAP signing finding','IOE Found','Synthetic evidence','SI000160','Privilege Escalation','Harden']], '', 'synthetic.csv', {toolId:'purple-knight'}).analysis.records[0]; const root = createRoot(document.getElementById('root')); let include = false; let resultsOpen = false; function render() { root.render({}} onNext={()=>{}} onReview={patch=>{include=patch.include;render();}} onResults={()=>{resultsOpen=true;render();}} resultsOpen={resultsOpen}/>); } render();`, resolveDir: process.cwd(), loader: 'tsx' }, jsx: 'automatic', bundle: true, write: false, outdir: 'synthetic', format: 'iife', loader: { '.woff2': 'dataurl', '.woff': 'dataurl', '.png': 'dataurl', '.svg': 'dataurl' } }); const server = createServer((request, response) => { const file = bundle.outputFiles.find(file => request.url === '/' + file.path.split(/[\\/]/).at(-1)); response.setHeader('Content-Type', file ? (request.url.endsWith('.css') ? 'text/css' : 'text/javascript') : 'text/html'); response.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(); await page.goto(`http://127.0.0.1:${server.address().port}/`); await page.locator('.reader-primary-actions').waitFor(); for (const theme of ['dark', 'light']) { await page.evaluate(theme => { document.documentElement.dataset.theme = theme; }, theme); const disclosure = page.getByRole('button', { name: 'MITRE ATT&CK and D3FEND information', exact: true }); assert.equal(await disclosure.getAttribute('aria-expanded'), 'false'); assert.equal(await page.locator('.mitre-badge').count(), 0); await disclosure.focus(); await page.keyboard.press('Enter'); await page.locator('.mitre-badge').first().waitFor(); assert.equal(await page.locator('.mitre-badge').count(), 2); const surface = await page.locator('.mitre-disclosure').evaluate(element => { const css = getComputedStyle(element); const button = getComputedStyle(element.querySelector('button')); return { background: css.backgroundColor, border: css.borderTopWidth, shadow: css.boxShadow, buttonBackground: button.backgroundColor, buttonBorder: button.borderTopWidth }; }); assert.deepEqual(surface, { background: 'rgba(0, 0, 0, 0)', border: '0px', shadow: 'none', buttonBackground: 'rgba(0, 0, 0, 0)', buttonBorder: '0px' }); await page.keyboard.press('Space'); await page.waitForFunction(() => !document.querySelector('.mitre-badge')); for (const width of [1200, 620, 320]) { await page.setViewportSize({ width, height: 900 }); const geometry = await page.locator('.reader-primary-actions').evaluate(group => [...group.children].map(action => { const rect = action.getBoundingClientRect(); return { x: rect.x, y: rect.y, right: rect.right, height: rect.height, text: action.textContent }; })); assert.deepEqual(geometry.map(action => action.text), ['AI search', '', 'Results']); assert.ok(geometry.every(action => Math.abs(action.y - geometry[0].y) < 1)); assert.ok(geometry[0].right < geometry[1].x && geometry[1].right < geometry[2].x); assert.ok(geometry[0].x >= 0 && geometry[2].right <= width); } const bookmark = page.getByRole('button', { name: 'Bookmark', exact: true }); const previous = await bookmark.getAttribute('aria-pressed'); await bookmark.click(); await page.waitForFunction(previous => document.querySelector('.bookmark-btn').getAttribute('aria-pressed') !== previous, previous); await page.getByRole('button', { name: 'Results', exact: true }).click(); assert.ok(await page.locator('.results-detail-btn').evaluate(button => button.classList.contains('is-open'))); } console.log('Finding actions: both themes, 1200/620/320px, icon-only bookmark, Results and frameless MITRE disclosure with Enter/Space passed.'); } finally { await browser?.close(); await new Promise(resolve => server.close(resolve)); }