web-access-smoke.cjs RawHistoryFolder
1// Isolated profile only: rotates access and disconnects all browser views.
2const { chromium } = require(process.env.PLAYWRIGHT_MODULE || 'playwright');
3const { execFileSync } = require('node:child_process');
4const assert = require('node:assert/strict');
5(async () => {
6 if (!process.env.VEV_BINARY || !process.env.VEV_ENV) throw new Error('VEV_BINARY and isolated VEV_ENV are required');
7 const link = flag => execFileSync(process.env.VEV_BINARY, [flag], { encoding: 'utf8' }).match(/http:\/\/127\.0\.0\.1:8778\/#token=[A-Za-z0-9_-]+/)[0];
8 const first = link('--web-daemon');
9 assert.equal(link('--web-daemon'), first);
10 const browser = await chromium.launch({ executablePath: process.env.CHROMIUM_PATH });
11 try {
12 const page = await browser.newPage();
13 await page.goto(first);
14 await page.waitForFunction(() => document.querySelector('#status').textContent === 'Connected');
15 await page.waitForFunction(() => Number(document.querySelector('#view-count').textContent) >= 1);
16 const initial = Number(await page.locator('#view-count').textContent());
17 assert.equal(await page.locator('#view-description').textContent(), `Connected browser terminal views: ${initial}`);
18 const button = page.locator('#palette');
19 const normal = await button.evaluate(node => ({ color: getComputedStyle(node).color, background: getComputedStyle(node).backgroundColor, border: getComputedStyle(node).borderTopWidth }));
20 await button.hover();
21 const hover = await button.evaluate(node => ({ color: getComputedStyle(node).color, background: getComputedStyle(node).backgroundColor }));
22 assert.equal(normal.border, '0px');
23 assert.equal(hover.background, normal.background);
24 assert.notEqual(hover.color, normal.color);
25 const other = await browser.newPage();
26 await other.goto(first);
27 await other.waitForFunction(() => document.querySelector('#status').textContent === 'Connected');
28 await page.waitForFunction(n => Number(document.querySelector('#view-count').textContent) === n + 1, initial);
29 assert.equal(await page.locator('#connection').getAttribute('data-state'), 'connected');
30 await other.close();
31 await page.waitForFunction(n => Number(document.querySelector('#view-count').textContent) === n, initial);
32 const next = link('--web-renew-token');
33 assert.notEqual(next, first);
34 await page.waitForFunction(() => document.querySelector('#status').textContent.startsWith('Disconnected'));
35 const oldStatus = await page.evaluate(async () => (await fetch('/health')).status);
36 assert.equal(oldStatus, 401);
37 assert.equal(await page.locator('#view-description').textContent(), 'Connected browser terminal views: unknown');
38 await page.locator('#reconnect').click();
39 await page.waitForFunction(() => document.querySelector('#status').textContent === 'Authentication required');
40 assert.equal(await page.locator('#help').isVisible(), true);
41 assert.equal(await page.locator('#reconnect').isVisible(), false);
42 const revoked = await browser.newPage();
43 await revoked.goto(first);
44 await revoked.waitForFunction(() => document.querySelector('#status').textContent === 'Authentication required');
45 await revoked.goto(next);
46 await revoked.waitForFunction(() => document.querySelector('#status').textContent === 'Connected');
47 assert.equal(await revoked.locator('#help').isVisible(), false);
48 await revoked.close();
49 await page.goto(next);
50 await page.waitForFunction(() => document.querySelector('#status').textContent === 'Connected');
51 console.log('Web access smoke passed: stable live token, view count, rotation, cookie revocation, reconnect.');
52 } finally { await browser.close(); }
53})().catch(error => { console.error(error); process.exitCode = 1; });