Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/dev/verify_crystalfull.mjs

4.8 KiB, 1 run

created by r2519314175:327, 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// verify_crystalfull.mjs — the crystal face's full-screen toggle (piece b).
2//
3// The lane that wrote the toggle died mid-verification, so for a while nothing
4// drove it. What its own comments promise, and what is held to here:
5//
6// * the control appears on the CRYSTAL face and nowhere else;
7// * pressing it sets `data-cfull`, which takes the top bar, the rail and the
8// dock away;
9// * Escape leaves it, and the control is still on screen to leave it with;
10// * leaving the crystal face puts the mode down;
11// * it does not survive a reload.
12//
13// node dev/verify_crystalfull.mjs
14//
15// It writes no path down: `harness.mjs` is imported relative to this file, and the one
16// screenshot goes to the harness scratch root — never into `www/`, whose bytes ship.
17import { open, scratch } from './harness.mjs';
18
19let failures = 0;
20const check = (cond, msg, detail) => {
21 console.log((cond ? ' ok ' : ' FAIL ') + msg + (detail != null ? ' — ' + detail : ''));
22 if (!cond) failures++;
23};
24
25const state = (p) => p.evaluate(() => {
26 const drawn = (sel) => { const e = document.querySelector(sel);
27 return !!(e && e.getClientRects().length); };
28 const b = document.getElementById('crystal-full-btn');
29 return {
30 attr: document.documentElement.getAttribute('data-cfull'),
31 btn: b ? { drawn: !!b.getClientRects().length, pressed: b.getAttribute('aria-pressed'),
32 label: b.getAttribute('aria-label'), word: (document.getElementById('crystal-full-txt') || {}).textContent } : null,
33 topbar: drawn('.topbar'),
34 rail: drawn('#panel-rail'),
35 dock: drawn('.dock'),
36 bar: drawn('.panel.ai .crystal-bar'),
37 frame: drawn('#crystal-frame-wrap'),
38 body: drawn('#crystal-body'),
39 };
40});
41
42const s = await open({ name: 'cfull', connect: false });
43const p = s.page;
44await p.waitForTimeout(1500);
45
46try {
47 // A seeded default Diamond; the face it opens on is the crystal.
48 await p.evaluate(() => {
49 const box = document.querySelector('.diamond-box');
50 if (box) box.click();
51 });
52 await p.waitForTimeout(1800);
53
54 const rest = await state(p);
55 console.log(' rest ' + JSON.stringify(rest));
56 check(!!rest.btn && rest.btn.drawn, 'the control is on the crystal face');
57 check(rest.btn && rest.btn.pressed === 'false', 'and says it is not pressed');
58 check(rest.btn && !rest.btn.word, 'with no word beside the glyph while the mode is off',
59 JSON.stringify(rest.btn && rest.btn.word));
60 check(rest.attr === null, 'and nothing is covering the app');
61
62 await p.click('#crystal-full-btn');
63 await p.waitForTimeout(500);
64 const on = await state(p);
65 console.log(' on ' + JSON.stringify(on));
66 check(on.attr === '1', 'pressing it sets data-cfull');
67 check(!on.topbar && !on.rail && !on.dock, 'the top bar, the rail and the dock go',
68 JSON.stringify({ topbar: on.topbar, rail: on.rail, dock: on.dock }));
69 check(on.btn && on.btn.drawn, 'AND THE WAY OUT IS STILL ON SCREEN');
70 check(on.btn && on.btn.pressed === 'true' && /exit/i.test(on.btn.label || ''),
71 'saying what pressing it will do', JSON.stringify(on.btn));
72 check(!!(on.btn && on.btn.word), 'with the word beside the glyph', JSON.stringify(on.btn && on.btn.word));
73 check(on.body, 'and the crystal is still drawn (reflow did not tear it down)');
74 await p.screenshot({ path: scratch('cfull-on.png') });
75
76 // Escape, from the app's own focus.
77 await p.keyboard.press('Escape');
78 await p.waitForTimeout(400);
79 const esc = await state(p);
80 check(esc.attr === null && esc.topbar && esc.rail, 'Escape leaves it', JSON.stringify(esc.attr));
81
82 // Leaving the crystal face puts the mode down rather than leaving a covered
83 // app with no subject.
84 await p.click('#crystal-full-btn');
85 await p.waitForTimeout(400);
86 check((await state(p)).attr === '1', 'back in');
87 await p.evaluate(() => { const b = document.getElementById('dview-chat'); if (b) b.click(); });
88 await p.waitForTimeout(800);
89 const face = await state(p);
90 check(face.attr === null, 'switching to the chat face puts the mode down');
91 check(!(face.btn && face.btn.drawn), 'and the control goes with the face it belongs to');
92
93 // It does not survive a reload.
94 await p.evaluate(() => { const b = document.getElementById('dview-crystal'); if (b) b.click(); });
95 await p.waitForTimeout(700);
96 await p.click('#crystal-full-btn');
97 await p.waitForTimeout(400);
98 check((await state(p)).attr === '1', 'in again, before the reload');
99 await p.reload({ waitUntil: 'domcontentloaded' });
100 await p.waitForTimeout(1500);
101 check((await state(p)).attr === null, 'a reload does not come back inside the mode');
102} catch (e) {
103 console.log(' FAIL threw — ' + (e && e.message));
104 failures++;
105} finally {
106 const errs = s.errs.filter(e => !/favicon|manifest|502|Bad Gateway|gateway/i.test(e));
107 if (errs.length) console.log(' console errors: ' + errs.slice(0, 6).join(' | '));
108 await s.close();
109}
110console.log(failures ? failures + ' failure(s)' : 'all checks passed');
111process.exit(failures ? 1 : 0);