Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/dev/verify_webpanel.mjs

5.5 KiB, 1 run

created by r2519314175:807, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1// The read-only text copy must be torn down when a new page opens, and the
2// panel must refuse to frame a loopback address. Both exercised via the real
3// DaimondWeb driver in the loaded page — no network needed.
4//
5// PROVED AGAINST TWO BREAKS FIRST, because both checks read a value that is
6// `false`/`none` in more than one way:
7// --break keepoverlay the fresh page is never opened, so the old text copy
8// is still standing and the teardown check must go red.
9// --break framehost the loopback probe is aimed at our own blob instead,
10// which the panel DOES frame, so the refusal check must
11// go red. Without this the check cannot tell a refusal
12// from an open that never happened.
13//
14// node dev/verify_webpanel.mjs --break keepoverlay # expected to FAIL
15// node dev/verify_webpanel.mjs --break framehost # expected to FAIL
16// node dev/verify_webpanel.mjs # and then, clean
17import fs from 'node:fs';
18import path from 'node:path';
19import { fileURLToPath } from 'node:url';
20import { open, shot, errors } from './harness.mjs';
21import { GW_URL } from './ports.mjs';
22
23const HERE = path.dirname(fileURLToPath(import.meta.url));
24const WEBJS = path.join(HERE, '..', 'www', 'js', 'web.js');
25
26const ok = [], bad = [];
27const check = (name, pass, detail) => {
28 (pass ? ok : bad).push(name + (detail ? ' — ' + detail : ''));
29 console.log((pass ? ' ok ' : ' FAIL ') + name + (detail ? ' — ' + detail : ''));
30};
31
32const BREAK = (() => {
33 const i = process.argv.indexOf('--break');
34 return i > 0 ? String(process.argv[i + 1] || '') : '';
35})();
36if (BREAK && !['keepoverlay', 'framehost'].includes(BREAK)) {
37 console.error(`unknown break '${BREAK}'; known: keepoverlay, framehost`);
38 process.exit(2);
39}
40
41const s = await open({ name: 'webpanel' });
42if (BREAK) console.log(`\n*** RUNNING UNDER --break ${BREAK}: failures below are the point ***\n`);
43
44const r = await s.page.evaluate(async ([brk, GW_URL]) => {
45 const W = window.DaimondWeb;
46 const out = { hasDriver: !!W };
47 if (!W) return out;
48 const body = document.getElementById('web-body') || document.querySelector('.web-body');
49 out.hasBody = !!body;
50 // `_showTextForTest` used to be called here. There is no such export on
51 // DaimondWeb and there never was, so the call did nothing and the overlay
52 // below was always the hand-built one.
53 // A page of our own, so nothing here needs the network.
54 const blob = URL.createObjectURL(new Blob(['<h1>fresh</h1>'], { type: 'text/html' }));
55 // The overlay is seeded by hand in showText's own shape and under showText's
56 // own id: `hideText()` finds it by that id, so this exercises the real
57 // teardown even though the text itself was not fetched by the gateway.
58 let pre = document.getElementById('web-text');
59 if (!pre) { pre = document.createElement('div'); pre.id = 'web-text'; (body || document.body).appendChild(pre); }
60 pre.style.display = ''; pre.innerHTML = '<div class="web-text-body">GITHUB TEXT</div>';
61 out.beforeOpen = { display: pre.style.display, text: pre.textContent };
62
63 if (brk !== 'keepoverlay') {
64 try { await W.open(blob); } catch (e) { out.openErr = e.message; }
65 } else {
66 out.skippedOpen = true;
67 }
68 const after = document.getElementById('web-text');
69 out.afterOpenDisplay = after ? after.style.display : 'removed';
70 out.afterOpenText = after ? after.textContent : '';
71
72 // Loopback must be refused (not framed). Under `framehost` the same question
73 // is asked of a page the panel is entitled to frame.
74 const probe = brk === 'framehost' ? blob : `${GW_URL}/api/balance`;
75 out.probe = brk === 'framehost' ? 'our own blob' : probe;
76 try {
77 const res = await W.open(probe);
78 out.loopback = { framed: res.framed, driver: res.driver };
79 } catch (e) { out.loopbackErr = e.message; }
80 return out;
81}, [BREAK, GW_URL]);
82console.log(JSON.stringify(r, null, 2));
83await shot(s, 'webpanel-after');
84
85check('the web panel driver and its body are on the page', r.hasDriver && r.hasBody,
86 `driver ${!!r.hasDriver}, body ${!!r.hasBody}`);
87// The overlay is seeded by hand, so the id it is seeded under has to be the one
88// the app's own `showText` uses -- otherwise this file tears down its own div
89// and calls that a pass while the real copy stays on the screen.
90const ID = "pre.id = 'web-text';";
91const seeded = fs.readFileSync(WEBJS, 'utf8').split(ID).length - 1;
92check('the id the overlay is seeded under is the id showText uses', seeded === 1,
93 `"${ID}" appears ${seeded} times in www/js/web.js`);
94check('a read-only text copy is standing before the next page opens',
95 !!(r.beforeOpen && r.beforeOpen.text), JSON.stringify(r.beforeOpen));
96check('A FRESH PAGE TEARS THE OLD TEXT COPY DOWN — no site\'s words under another site\'s header',
97 (r.afterOpenDisplay === 'none' || r.afterOpenDisplay === 'removed') && !r.afterOpenText,
98 `display ${r.afterOpenDisplay}, text ${JSON.stringify((r.afterOpenText || '').slice(0, 40))}`
99 + (r.skippedOpen ? ' (no page was opened)' : '') + (r.openErr ? ' openErr: ' + r.openErr : ''));
100check('A LOOPBACK ADDRESS IS REFUSED THE FRAME',
101 !!r.loopback && r.loopback.framed === false,
102 r.loopback ? `${r.probe}: framed=${r.loopback.framed} driver=${r.loopback.driver}` : 'threw: ' + r.loopbackErr);
103
104const errs = errors(s).filter(e => !/502|Bad Gateway/.test(e));
105check('nothing threw', errs.length === 0, errs.slice(0, 2).join(' | '));
106
107await s.close();
108console.log(`\n${ok.length} passed, ${bad.length} failed`);
109if (bad.length) { bad.forEach(x => console.log(' FAILED: ' + x)); process.exit(1); }