#!/usr/bin/env node
/*
* Pins how client.html leaves a session (#257).
*
* A fullscreen-on-connect session runs the client in a same-origin frame on
* the Connections tab. Every other page refuses to load in a frame
* (frame-ancestors 'none'), so a navigation from inside the frame (Home in
* the Ctrl+Alt+Shift panel, reconnect, the disconnected overlay) that only
* moved the frame showed the browser's "cannot open this page" in place of
* the session. Every navigation must go through rgGo(), which moves the
* whole tab when embedded.
*
* Usage: node tests/client-navigation.mjs
*/
import { readFile } from 'node:fs/promises';
import { dirname, resolve, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import vm from 'node:vm';
import assert from 'node:assert/strict';
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const html = await readFile(join(root, 'static/client.html'), 'utf8');
function lift(name) {
const start = html.indexOf(`function ${name}(`);
assert.notEqual(start, -1, `${name}() must exist in client.html`);
let i = html.indexOf('{', start), depth = 0;
for (; i < html.length; i++) {
if (html[i] === '{') depth++;
else if (html[i] === '}' && --depth === 0) break;
}
return { start, end: i + 1, src: html.slice(start, i + 1) };
}
const go = lift('rgGo');
// 1. Nothing navigates except through rgGo.
const outside = html.slice(0, go.start) + html.slice(go.end);
for (const pattern of [/location\.href\s*=/, /location\.replace\(/, /location\.assign\(/]) {
assert.doesNotMatch(outside, pattern, `client.html must navigate through rgGo(), not ${pattern}`);
}
// 2. rgGo moves the whole tab when embedded, and only this page otherwise.
function run(embedded) {
const top = { location: { href: '/client/x' } };
const self = { location: { href: '/client/x' } };
const ctx = { embedded, window: { top, location: self.location } };
vm.createContext(ctx);
vm.runInContext(go.src, ctx);
ctx.rgGo('/connections.html');
return { top: top.location.href, self: self.location.href };
}
let r = run(true);
assert.equal(r.top, '/connections.html', 'embedded: the whole tab goes');
assert.equal(r.self, '/client/x', 'embedded: the frame itself is not navigated');
r = run(false);
assert.equal(r.self, '/connections.html', 'a normal tab navigates itself');
console.log('client-navigation: ok');