Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/dev/probe_toolspanel.mjs

4.5 KiB, 1 run

created by r2519314175:89, 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// probe_toolspanel.mjs — look at the Tools panel, in the states a reader meets it.
2//
3// Not a check: a set of screenshots for ink-level QC. Three states (as shipped, with a
4// pack for sale, with one bought) and a narrow stage seat, because the panel is a stage
5// guest and the stage can be half a phone wide.
6//
7// eval "$(bash dev/world.sh 5 --env)"
8// node dev/probe_toolspanel.mjs
9import { open, shot, scratch } from './harness.mjs';
10import fs from 'node:fs';
11
12const PROFILE = scratch('pw', 'toolsprobe');
13fs.rmSync(PROFILE, { recursive: true, force: true });
14
15const CORS = { 'access-control-allow-origin': '*', 'access-control-allow-headers': '*' };
16const json = (b) => ({ status: 200, contentType: 'application/json', headers: CORS, body: JSON.stringify(b) });
17
18let catalogue = [];
19
20const s = await open({ name: 'toolsprobe', profile: PROFILE, signIn: false, connect: false });
21const p = s.page;
22
23await p.route('**/api/account', r => r.fulfill(json({ ok: true })));
24await p.route('**/api/auth/challenge', r => r.fulfill(json({ ok: true, challenge: 'c', challenge_id: 'i' })));
25await p.route('**/api/auth/verify', r => r.fulfill(json({ ok: true })));
26await p.route('**/api/balance', r => r.fulfill(json({ ok: true, credits_minor: 5000, currency: 'usd', entries: [] })));
27await p.route('**/api/licence', r => r.fulfill(json({ ok: true, licence: true, held: true, currency: 'usd' })));
28await p.route('**/api/tools', r => r.fulfill(json({ ok: true, credits_minor: 5000, tools: catalogue })));
29
30await p.goto(process.env.DAIMOND_APP || 'http://localhost:8777', { waitUntil: 'domcontentloaded' });
31const { signInAs } = await import('./harness.mjs');
32await signInAs(s, 'toolsprobe');
33await p.waitForTimeout(2500);
34
35const draw = async (label, toShelf) => {
36 await p.evaluate(() => { window.DaimondPanels.show('tools'); window.DaimondTools.reload(); });
37 await p.waitForTimeout(1000);
38 if (toShelf) {
39 await p.evaluate(() => {
40 const secs = [...document.querySelectorAll('#tools-body > .tools-sec')];
41 if (secs.length > 1) secs[secs.length - 1].scrollIntoView({ block: 'start' });
42 });
43 await p.waitForTimeout(300);
44 }
45 // The rail row, and the rail row after `DaimondAdmin.status()` has been asked again by
46 // hand. If the second differs from the first the row is not being redrawn on its own,
47 // which is a defect in daimond.js and not in this panel — `status()` returns early
48 // when the money rows draw, and `proRow()`, `tools()` and `storage()` sit after it.
49 const rail = await p.evaluate(() => {
50 const r = document.getElementById('astat-tools');
51 return r ? r.innerText.replace(/\s+/g, ' ').trim() : '(no row)';
52 });
53 const forced = await p.evaluate(() => {
54 if (window.DaimondAdmin && DaimondAdmin.status) DaimondAdmin.status();
55 const r = document.getElementById('astat-tools');
56 return r ? r.innerText.replace(/\s+/g, ' ').trim() : '(no row)';
57 });
58 if (forced !== rail) console.log(' ! the rail is stale:', rail, '→', forced, 'once status() is re-asked');
59 console.log(label, '— rail:', rail, '— counts:',
60 JSON.stringify(await p.evaluate(() => window.DaimondTools.counts())));
61 await shot(s, label);
62};
63
64try {
65 await draw('toolspanel-shipped');
66
67 // Opened, which is the state the disclosure exists for.
68 await p.evaluate(() => {
69 for (const c of document.querySelectorAll('#tools-body .cap')) {
70 const b = c.querySelector('.cap-more');
71 if (b && c.getAttribute('data-cap') === 'browsing') b.click();
72 }
73 });
74 await p.waitForTimeout(300);
75 await shot(s, 'toolspanel-open');
76
77 catalogue = [
78 { tool: 'typst', name: 'Typesetting', blurb: 'Daimond typesets a document into a finished PDF.', price_minor: 2500, unlocked: false, currency: 'usd' },
79 { tool: 'research', name: 'Research', blurb: 'Daimond runs a line of enquiry: searching, reading, and keeping what it found where you can check it.', price_minor: 4500, unlocked: false, currency: 'usd' },
80 ];
81 await draw('toolspanel-shelf', true);
82
83 catalogue[0].unlocked = true;
84 await draw('toolspanel-owned', true);
85
86 // A narrow stage seat, which is where a long capability name and a Buy button fight.
87 await p.setViewportSize({ width: 720, height: 950 });
88 await p.waitForTimeout(600);
89 await draw('toolspanel-narrow', true);
90
91 // Overflow: nothing on this panel may push the body sideways.
92 const over = await p.evaluate(() => {
93 const b = document.getElementById('tools-body');
94 return { scroll: b.scrollWidth, client: b.clientWidth };
95 });
96 console.log('tools-body overflow:', JSON.stringify(over));
97} finally {
98 await s.close();
99}