const assert = require('node:assert/strict'); const test = require('node:test'); const fs = require('node:fs/promises'); const os = require('node:os'); const path = require('node:path'); const Module = require('node:module'); const { pathToFileURL } = require('node:url'); const { promisify } = require('node:util'); const run = promisify(require('node:child_process').execFile); test('generated flowcharts render offline and source clicks retain the actual location', async () => { assert.ok(process.env.DEVER_TEST_BIN); assert.ok(process.env.DEVER_BROWSER_TOOLS, 'directory containing existing playwright-core and @sparticuz/chromium'); const tools = Module.createRequire(path.join(process.env.DEVER_BROWSER_TOOLS, '..', 'package.json')); const { chromium: playwright } = tools('playwright-core'); const chromium = tools('@sparticuz/chromium').default; const root = await fs.mkdtemp(path.join(os.tmpdir(), 'dever flow browser ')); const extension = path.resolve(__dirname, '../../editor/vscode'); const project = path.join(root, 'project'); const subscriptions = []; let browser; const originalLoad = Module._load; try { await run(process.env.DEVER_TEST_BIN, ['new', project]); await run(process.env.DEVER_TEST_BIN, ['inspect', project, '--links']); const uri = filename => ({ fsPath: filename, toString: () => pathToFileURL(filename).toString() }); const panels = []; const vscode = { Uri: { joinPath: (base, ...parts) => uri(path.join(base.fsPath, ...parts)) }, ViewColumn: { Beside: 2 }, window: { createWebviewPanel() { const panel = { dispose() {}, onDidDispose() {}, webview: { cspSource: 'https://dever-preview.test', asWebviewUri: uri => `https://dever-preview.test/${path.basename(uri.fsPath)}`, onDidReceiveMessage: () => ({ dispose() {} }) } }; panels.push(panel); return panel; } } }; Module._load = function(request, ...rest) { return request === 'vscode' ? vscode : originalLoad.call(this, request, ...rest); }; const { openFlowPreview } = require('../../editor/vscode/dist/flow-preview.cjs'); Module._load = originalLoad; browser = await playwright.launch({ executablePath: await chromium.executablePath(), args: chromium.args, headless: true }); const page = await browser.newPage(); page.on('pageerror', error => console.error('Browser error:', error.message)); page.on('console', message => { if (message.type() === 'error') console.error('Browser console:', message.text()); }); const scripts = new Map(await Promise.all(['flow-browser.js', 'mermaid.js'].map(async name => [`https://dever-preview.test/${name}`, await fs.readFile(path.join(extension, 'dist', name), 'utf8')]))); const messages = []; await page.exposeFunction('deverMessage', message => messages.push(message)); await page.route('**/*', route => scripts.has(route.request().url()) ? route.fulfill({ body: scripts.get(route.request().url()), contentType: 'text/javascript' }) : route.abort()); const projects = [project]; for (const relative of ['test/rust/fixtures/auth', 'test/rust/fixtures/adapters', 'skills/assets/examples/command', 'skills/assets/examples/external-lib']) { const copy = path.join(root, path.basename(relative)); await fs.cp(path.resolve(__dirname, '../..', relative), copy, { recursive: true }); await run(process.env.DEVER_TEST_BIN, ['inspect', copy, '--links']); projects.push(copy); } if (process.env.DEVER_FLOW_PROJECT) projects.push(process.env.DEVER_FLOW_PROJECT); const targets = []; for (const owner of projects) { for await (const filename of fs.glob('module/*/*/link.md', { cwd: owner })) targets.push({ filename: path.join(owner, filename), owner }); } let count = 0; for (const { filename, owner } of targets) { console.log(`Rendering ${filename}`); await openFlowPreview({ subscriptions, extensionUri: uri(extension) }, uri(filename), owner); const html = panels.at(-1).webview.html; const expected = (html.match(/class="language-mermaid"/g) || []).length; const nonce = /nonce="([^"]+)"/.exec(html)[1]; const bridge = ``; await page.goto('about:blank'); await page.setContent(html.replace(' typeof globalThis.mermaid?.render), 'function'); await page.waitForSelector('body[data-rendered="true"]', { timeout: 60000 }); assert.deepEqual(await page.locator('.dever-flow-error').allTextContents(), [], filename); assert.equal(await page.locator('.dever-flow > svg').count(), expected, filename); assert.ok(expected > 0, filename); count += expected; const source = page.locator('.dever-flow a').first(); const href = await source.getAttribute('href') || await source.getAttribute('xlink:href'); await source.click(); await page.waitForTimeout(20); assert.deepEqual(messages.at(-1), { type: 'open', href }); assert.match(href, /\.dever(?:\.md)?#L\d+,\d+$/); if (process.env.DEVER_FLOW_SCREENSHOT && path.basename(path.dirname(filename)) === 'audit') { await page.screenshot({ path: process.env.DEVER_FLOW_SCREENSHOT, fullPage: true }); } } console.log(`Rendered ${count} real generated diagrams in ${targets.length} pages without network dependencies`); } finally { Module._load = originalLoad; await browser?.close(); for (const subscription of subscriptions) subscription.dispose(); await fs.rm(root, { recursive: true }); } });