web-visual-smoke.cjs RawHistoryFolder
1// Run against an isolated gateway. Supply PLAYWRIGHT_MODULE, VEV_BINARY and VEV_ENV.
2// The test creates sessions/panes; it never targets an existing named session.
3const { chromium } = require(process.env.PLAYWRIGHT_MODULE || 'playwright');
4const { execFileSync } = require('node:child_process');
5const assert = require('node:assert/strict');
6
7(async () => {
8 if (!process.env.VEV_BINARY || !process.env.VEV_ENV) throw new Error('VEV_BINARY and isolated VEV_ENV are required');
9 const browser = await chromium.launch({
10 executablePath: process.env.CHROMIUM_PATH || undefined,
11 headless: true
12 });
13 try {
14 const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
15 const errors = [];
16 page.on('pageerror', error => errors.push(error.message));
17 const output = execFileSync(process.env.VEV_BINARY, ['--web-daemon'], { encoding: 'utf8' });
18 const token = output.match(/#token=([A-Za-z0-9_-]+)/)[1];
19 await page.goto(`http://127.0.0.1:8778/#token=${token}`);
20 const connected = () => page.waitForFunction(() => document.querySelector('#status').textContent.startsWith('Connected'));
21 const contains = text => page.waitForFunction(text => document.querySelector('.vev-terminal__accessible-output').textContent.includes(text), text);
22 await connected();
23 assert.equal(new URL(page.url()).hash, '');
24 await page.keyboard.type("printf '\\033[2J\\033[HDIMCHECK\\n'");
25 await page.keyboard.press('Enter');
26 await contains('DIMCHECK');
27 const markerColor = () => page.evaluate(() => {
28 const cell = [...document.querySelectorAll('.vev-terminal__cell')].find(cell => cell.textContent === 'D');
29 return cell && getComputedStyle(cell).color;
30 });
31 const normalColor = await markerColor();
32 assert.ok(normalColor);
33 await page.locator('#palette').click();
34 await contains('Commands');
35 assert.notEqual(await markerColor(), normalColor, 'palette backdrop uses theme dimming');
36 await page.keyboard.press('Escape');
37 await page.waitForFunction(() => !document.querySelector('.vev-terminal__accessible-output').textContent.includes('Commands'));
38 assert.equal(await markerColor(), normalColor, 'closing the palette restores the theme');
39 await page.locator('#palette').click();
40 await contains('Commands');
41 await page.keyboard.type('SPR');
42 await page.keyboard.press('Enter');
43 await contains('│');
44 await page.keyboard.type("printf '\\033[2J\\033[HRIGHT-PANE\\n'");
45 await page.keyboard.press('Enter');
46 await contains('RIGHT-PANE');
47 await page.keyboard.press('Alt+h');
48 await page.keyboard.type("printf '\\033[2J\\033[HLEFT-PANE\\n'");
49 await page.keyboard.press('Enter');
50 await contains('LEFT-PANE');
51 const bounds = await page.locator('#terminal').boundingBox();
52 await page.mouse.click(bounds.x + bounds.width * .75, bounds.y + 90);
53 await page.keyboard.type('MOUSE-CHECK');
54 await contains('MOUSE-CHECK');
55 await page.keyboard.press('Control+c');
56 await page.setViewportSize({ width: 960, height: 600 });
57 await page.waitForFunction(() => document.querySelectorAll('.vev-terminal__row').length < 40);
58 await page.locator('#terminal').evaluate(root => {
59 const clipboardData = new DataTransfer();
60 clipboardData.setData('text/plain', 'paste');
61 root.querySelector('textarea').dispatchEvent(new ClipboardEvent('paste', { clipboardData, bubbles: true, cancelable: true }));
62 });
63 await page.waitForFunction(() => {
64 const rows = [...document.querySelectorAll('.vev-terminal__row')];
65 const right = rows.map(row => {
66 const cells = [...row.children];
67 const divider = cells.findIndex(cell => cell.textContent === '│');
68 return cells.slice(divider + 1).map(cell => cell.textContent).join('').trimEnd();
69 }).join('');
70 return right.includes('paste');
71 });
72 await page.keyboard.press('Control+c');
73 await page.reload();
74 await connected();
75 assert.deepEqual(errors, []);
76 console.log('Web visual smoke passed: auth, palette, split, keyboard, mouse input, resize, paste, reload.');
77 } finally {
78 await browser.close();
79 }
80})().catch(error => { console.error(error); process.exitCode = 1; });