annotate mrjunejune/test/theme_and_webp_test.js @ 272:41a49c29a28f

polish JRPG conversation experience Integrate desktop conversations into the utility panel, simplify the mobile frame, add modal destinations and a reusable Zenbu composer lab, and preserve explicit conversation resume behavior. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Fri, 07 Aug 2026 16:05:29 -0700
parents 056790c4fb0d
children e02e2036ef84
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
1 const assert = require('node:assert/strict');
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2 const fs = require('node:fs');
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3 const net = require('node:net');
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
4 const os = require('node:os');
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
5 const path = require('node:path');
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
6 const { spawn } = require('node:child_process');
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
7
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
8 const RUNFILES = process.env.JS_BINARY__RUNFILES;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
9 const WORKSPACE = process.env.JS_BINARY__WORKSPACE;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
10 let port;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
11 let baseUrl;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
12 const playwrightPath = path.join(
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
13 RUNFILES,
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
14 WORKSPACE,
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
15 'hg-web/e2e/node_modules/playwright-core',
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
16 );
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
17 const { chromium } = require(playwrightPath);
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
18 const browserSuite = process.env.MJJ_BROWSER_SUITE || 'all';
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
19 const runsSuite = name => browserSuite === 'all' || browserSuite === name;
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
20
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
21 function stopProcess(child) {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
22 if (!child || child.exitCode !== null) return Promise.resolve();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
23 child.kill('SIGTERM');
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
24 return new Promise(resolve => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
25 const timer = setTimeout(() => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
26 if (child.exitCode === null) child.kill('SIGKILL');
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
27 }, 3000);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
28 child.once('exit', () => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
29 clearTimeout(timer);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
30 resolve();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
31 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
32 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
33 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
34
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
35 async function waitForServer(child, logs) {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
36 const deadline = Date.now() + 15000;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
37 while (Date.now() < deadline) {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
38 if (child.exitCode !== null) {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
39 throw new Error(`Server exited with ${child.exitCode}\n${logs.join('')}`);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
40 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
41 try {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
42 const response = await fetch(baseUrl);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
43 if (response.ok) return;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
44 } catch {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
45 // Keep waiting for startup.
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
46 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
47 await new Promise(resolve => setTimeout(resolve, 100));
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
48 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
49 throw new Error(`Server startup timed out\n${logs.join('')}`);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
50 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
51
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
52 function listFiles(root) {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
53 const files = [];
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
54 for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
55 const absolute = path.join(root, entry.name);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
56 if (entry.isDirectory()) files.push(...listFiles(absolute));
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
57 else files.push(absolute);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
58 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
59 return files;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
60 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
61
258
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
62 function primitiveOwnershipViolations(source) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
63 const violations = [];
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
64 const stack = [];
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
65 const voidElements = new Set([
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
66 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
67 'meta', 'param', 'source', 'track', 'wbr',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
68 ]);
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
69 const ownerMap = {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
70 button: new Set(['zen-button']),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
71 select: new Set(['zen-field', 'zen-native-select', 'zen-select']),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
72 textarea: new Set(['zen-field', 'zen-textarea']),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
73 };
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
74
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
75 for (const token of source.matchAll(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
76 /<!--[\s\S]*?-->|<\/?([a-zA-Z][\w-]*)\b([^>]*)>/g,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
77 )) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
78 if (!token[1]) continue;
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
79 const name = token[1].toLowerCase();
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
80 if (token[0].startsWith('</')) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
81 while (stack.length) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
82 if (stack.pop() === name) break;
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
83 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
84 continue;
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
85 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
86
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
87 let owners = ownerMap[name];
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
88 if (name === 'input') {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
89 const type = /\btype\s*=\s*["']?([^"'\s>]+)/i.exec(token[2])?.[1]
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
90 ?.toLowerCase() || 'text';
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
91 if (type === 'checkbox') {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
92 owners = new Set(['zen-checkbox', 'zen-field', 'zen-switch']);
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
93 } else if (type === 'radio') {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
94 owners = new Set(['zen-field', 'zen-radio-group']);
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
95 } else if (type === 'range') {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
96 owners = new Set(['zen-field', 'zen-slider']);
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
97 } else if (type === 'date') {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
98 owners = new Set(['zen-calendar', 'zen-date-picker', 'zen-field']);
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
99 } else {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
100 owners = new Set([
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
101 'zen-combobox',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
102 'zen-command',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
103 'zen-field',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
104 'zen-input',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
105 'zen-input-group',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
106 'zen-input-otp',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
107 ]);
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
108 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
109 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
110 if (owners) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
111 const matchingOwners = stack.filter(ancestor => owners.has(ancestor));
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
112 if (matchingOwners.length !== 1) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
113 violations.push({
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
114 control: name,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
115 owners: matchingOwners,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
116 source: token[0],
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
117 });
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
118 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
119 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
120
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
121 if (!voidElements.has(name) && !token[0].endsWith('/>')) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
122 stack.push(name);
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
123 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
124 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
125 return violations;
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
126 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
127
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
128 async function sampleTheme(browser, theme) {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
129 const context = await browser.newContext({ colorScheme: 'dark' });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
130 await context.addInitScript(value => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
131 localStorage.setItem('theme-preference', value);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
132 }, theme);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
133 const page = await context.newPage();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
134 const errors = [];
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
135 await page.route('**/api/conversations**', async route => {
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
136 const request = route.request();
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
137 const url = new URL(request.url());
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
138 if (request.method() === 'POST' &&
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
139 url.pathname === '/api/conversations') {
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
140 await route.fulfill({
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
141 status: 201,
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
142 contentType: 'application/json',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
143 body: JSON.stringify({
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
144 id: '11111111-1111-4111-8111-111111111111',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
145 }),
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
146 });
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
147 return;
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
148 }
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
149 if (request.method() === 'POST' && url.pathname.endsWith('/turns')) {
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
150 await route.fulfill({
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
151 status: 200,
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
152 contentType: 'text/event-stream',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
153 body: [
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
154 'event: turn.accepted',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
155 'data: {"request_id":"request-1"}',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
156 '',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
157 'event: assistant.delta',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
158 'data: {"request_id":"request-1","delta":"Start with "}',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
159 '',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
160 'event: assistant.delta',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
161 'data: {"request_id":"request-1","delta":"the tools."}',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
162 '',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
163 'event: assistant.completed',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
164 'data: {"request_id":"request-1","content":"Start with the tools."}',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
165 '',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
166 'event: turn.done',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
167 'data: {"request_id":"request-1","failed":false,"aborted":false}',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
168 '',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
169 '',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
170 ].join('\n'),
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
171 });
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
172 return;
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
173 }
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
174 await route.fulfill({
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
175 status: 404,
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
176 contentType: 'application/json',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
177 body: JSON.stringify({ error: { message: 'Not found' } }),
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
178 });
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
179 });
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
180 page.on('pageerror', error => errors.push(`pageerror: ${error.message}`));
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
181 page.on('console', message => {
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
182 if (message.type() === 'error' &&
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
183 !message.text().startsWith('Failed to load resource:')) {
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
184 errors.push(`console: ${message.text()}`);
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
185 }
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
186 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
187 page.on('requestfailed', request => {
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
188 if (request.url().startsWith('blob:') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
189 request.failure()?.errorText === 'net::ERR_ABORTED') {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
190 return;
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
191 }
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
192 if (request.method() === 'DELETE' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
193 request.url().includes('/api/download/') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
194 request.failure()?.errorText === 'net::ERR_ABORTED') {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
195 return;
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
196 }
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
197 if (request.method() === 'POST' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
198 request.url().endsWith('/api/latex/render') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
199 request.failure()?.errorText === 'net::ERR_ABORTED') {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
200 return;
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
201 }
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
202 errors.push(`requestfailed: ${request.url()} ${request.failure()?.errorText || ''}`);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
203 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
204 page.on('response', response => {
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
205 if (response.status() === 404 &&
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
206 response.url().endsWith(
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
207 '/api/conversations/00000000-0000-4000-8000-000000000000'
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
208 )) {
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
209 return;
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
210 }
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
211 if (response.status() >= 400) {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
212 errors.push(`response: ${response.status()} ${response.url()}`);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
213 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
214 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
215
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
216 await page.goto(baseUrl, { waitUntil: 'networkidle' });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
217 await page.waitForFunction(() => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
218 const canvas = document.querySelector('#background');
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
219 if (!canvas) return false;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
220 const data = canvas.getContext('2d').getImageData(
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
221 0,
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
222 0,
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
223 canvas.width,
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
224 canvas.height,
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
225 ).data;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
226 for (let index = 3; index < data.length; index += 4) {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
227 if (data[index] >= 20) return true;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
228 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
229 return false;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
230 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
231
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
232 const sample = await page.evaluate(() => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
233 const canvas = document.querySelector('#background');
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
234 const data = canvas.getContext('2d').getImageData(
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
235 0,
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
236 0,
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
237 canvas.width,
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
238 canvas.height,
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
239 ).data;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
240 let count = 0;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
241 let luminance = 0;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
242 for (let index = 0; index < data.length; index += 4) {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
243 if (data[index + 3] < 20) continue;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
244 count++;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
245 luminance +=
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
246 data[index] * 0.2126 +
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
247 data[index + 1] * 0.7152 +
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
248 data[index + 2] * 0.0722;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
249 }
256
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
250 const channels = value => value.match(/\d+(?:\.\d+)?/g)
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
251 .slice(0, 3)
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
252 .map(Number);
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
253 const colorLuminance = value => {
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
254 const converted = channels(value).map(channel => {
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
255 const normalized = channel / 255;
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
256 return normalized <= 0.04045
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
257 ? normalized / 12.92
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
258 : ((normalized + 0.055) / 1.055) ** 2.4;
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
259 });
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
260 return converted[0] * 0.2126 +
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
261 converted[1] * 0.7152 +
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
262 converted[2] * 0.0722;
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
263 };
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
264 const bodyStyle = getComputedStyle(document.body);
258
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
265 const themeButtonStyle = getComputedStyle(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
266 document.querySelector('#themeToggle'),
256
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
267 );
258
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
268 const foreground = colorLuminance(bodyStyle.color);
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
269 const contrastProbe = document.createElement('span');
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
270 contrastProbe.style.background = 'var(--zen-color-surface)';
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
271 document.body.append(contrastProbe);
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
272 const background = colorLuminance(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
273 getComputedStyle(contrastProbe).backgroundColor,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
274 );
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
275 contrastProbe.remove();
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
276 return {
258
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
277 backgroundRepeat: bodyStyle.backgroundRepeat,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
278 backgroundSize: bodyStyle.backgroundSize,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
279 bodyCoversViewport: document.body.getBoundingClientRect().height >=
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
280 innerHeight,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
281 componentReady: Boolean(customElements.get('zen-button')),
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
282 count,
256
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
283 fontFamily: getComputedStyle(document.body).fontFamily,
258
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
284 headerPaws: document.querySelectorAll(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
285 'header [data-zen-link-decoration]',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
286 ).length,
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
287 luminance: count ? luminance / count : 0,
256
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
288 textContrast: (Math.max(foreground, background) + 0.05) /
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
289 (Math.min(foreground, background) + 0.05),
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
290 rootTheme: document.documentElement.dataset.zenTheme || 'auto',
258
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
291 enhancedLinks: document.querySelectorAll(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
292 'zen-link[effect="paw"] > a > zen-icon[name="paw"]',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
293 ).length,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
294 links: document.querySelectorAll('a').length,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
295 pawLinks: [...document.querySelectorAll('a')].filter(link =>
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
296 !link.closest('zen-button') &&
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
297 link.dataset.zenLinkEffect !== 'none'
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
298 ).length,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
299 mainBackground: getComputedStyle(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
300 document.querySelector('main'),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
301 ).backgroundColor,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
302 themeButtonBackground: themeButtonStyle.backgroundColor,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
303 themeButtonBorder: themeButtonStyle.borderTopWidth,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
304 themeButtonShadow: themeButtonStyle.boxShadow,
256
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
305 themeLabel: document.querySelector('#themeName')?.textContent,
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
306 };
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
307 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
308
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
309 if (errors.length) throw new Error(`${theme}\n${errors.join('\n')}`);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
310 await context.close();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
311 return sample;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
312 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
313
256
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
314 async function testThemeCycle(browser) {
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
315 const context = await browser.newContext({ colorScheme: 'light' });
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
316 const page = await context.newPage();
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
317 await page.goto(baseUrl, { waitUntil: 'networkidle' });
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
318 const expected = ['paper', 'ink', 'playful', 'auto'];
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
319 for (const theme of expected) {
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
320 await page.locator('#themeToggle').click();
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
321 assert.equal(
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
322 await page.evaluate(() =>
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
323 document.documentElement.dataset.zenTheme || 'auto'
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
324 ),
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
325 theme,
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
326 );
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
327 assert.equal(
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
328 await page.evaluate(() => localStorage.getItem('theme-preference')),
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
329 theme,
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
330 );
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
331 }
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
332 await context.close();
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
333 }
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
334
258
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
335 async function testPlainField(browser) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
336 const page = await browser.newPage();
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
337 await page.goto(`${baseUrl}/tools/markdown_to_html`, {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
338 waitUntil: 'networkidle',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
339 });
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
340 await page.waitForFunction(() => customElements.get('zen-field'));
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
341 const state = await page.locator('zen-field[appearance="plain"]').evaluate(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
342 field => {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
343 const label = field.querySelector('label');
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
344 const textarea = field.querySelector('textarea');
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
345 const probe = document.createElement('span');
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
346 probe.style.border = '1px solid var(--accent)';
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
347 document.body.append(probe);
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
348 const accent = getComputedStyle(probe).borderColor;
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
349 probe.remove();
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
350 textarea.focus();
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
351 return {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
352 borderColor: getComputedStyle(textarea).borderColor,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
353 display: getComputedStyle(field).display,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
354 labelFor: label.htmlFor,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
355 accent,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
356 textareaId: textarea.id,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
357 };
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
358 },
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
359 );
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
360 assert.deepEqual(state, {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
361 accent: state.borderColor,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
362 borderColor: state.borderColor,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
363 display: 'contents',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
364 labelFor: 'input',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
365 textareaId: 'input',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
366 });
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
367 await page.close();
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
368 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
369
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
370 async function testButtonScale(browser) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
371 const page = await browser.newPage();
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
372 for (const route of [
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
373 '/talk',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
374 '/notes/login',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
375 '/tools/hls_player',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
376 '/tools/latex_editor',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
377 '/tools/markdown_to_html',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
378 '/tools/file_converter',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
379 '/offline.html',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
380 ]) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
381 await page.goto(`${baseUrl}${route}`, { waitUntil: 'networkidle' });
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
382 await page.waitForFunction(() => customElements.get('zen-button'));
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
383 const controls = await page.locator(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
384 'zen-button[size] > :is(button, a):not(#themeToggle)',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
385 ).evaluateAll(elements => elements.map(control => {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
386 const host = control.parentElement;
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
387 const style = getComputedStyle(control);
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
388 const hostStyle = getComputedStyle(host);
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
389 return {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
390 height: control.getBoundingClientRect().height,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
391 minimum: Number.parseFloat(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
392 hostStyle.getPropertyValue('--zenbu-control-height'),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
393 ) * Number.parseFloat(getComputedStyle(document.documentElement).fontSize),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
394 paddingBlock: style.paddingBlockStart,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
395 paddingVariable: Number.parseFloat(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
396 hostStyle.getPropertyValue('--zenbu-control-padding-block'),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
397 ) * Number.parseFloat(getComputedStyle(document.documentElement).fontSize),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
398 size: host.getAttribute('size'),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
399 };
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
400 }));
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
401 assert.ok(controls.length > 0, route);
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
402 for (const control of controls) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
403 assert.match(control.size, /^(?:xs|sm|md|lg|xl)$/);
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
404 assert.ok(control.height >= control.minimum - 1, JSON.stringify(control));
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
405 assert.ok(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
406 Math.abs(Number.parseFloat(control.paddingBlock) -
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
407 control.paddingVariable) < 1,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
408 JSON.stringify(control),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
409 );
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
410 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
411 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
412 await page.close();
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
413 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
414
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
415 async function testDynamicButtonOwnership(browser) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
416 const page = await browser.newPage();
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
417 await page.goto(baseUrl, { waitUntil: 'networkidle' });
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
418 await page.evaluate(() => {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
419 window.dispatchEvent(new Event('beforeinstallprompt', {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
420 cancelable: true,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
421 }));
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
422 });
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
423 const state = await page.locator('#pwa-install-btn').evaluate(button => ({
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
424 ownerCount: button.closest('zen-button') ? 1 : 0,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
425 appearance: button.closest('zen-button')?.getAttribute('appearance'),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
426 size: button.closest('zen-button')?.getAttribute('size'),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
427 }));
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
428 assert.deepEqual(state, {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
429 appearance: 'plain',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
430 ownerCount: 1,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
431 size: 'md',
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
432 });
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
433 await page.close();
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
434 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
435
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
436 async function testResumePrint(browser) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
437 const page = await browser.newPage();
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
438 await page.emulateMedia({ media: 'print' });
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
439 await page.goto(`${baseUrl}/resume`, { waitUntil: 'networkidle' });
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
440 assert.equal(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
441 await page.locator('.info > a[href="/public/resume.pdf"]').isVisible(),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
442 false,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
443 );
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
444 await page.close();
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
445 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
446
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
447 async function testComposerLab(browser) {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
448 const context = await browser.newContext({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
449 serviceWorkers: 'block',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
450 viewport: { width: 390, height: 844 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
451 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
452 const page = await context.newPage();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
453 await page.goto(`${baseUrl}/public/composer-lab.html`, {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
454 waitUntil: 'networkidle',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
455 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
456 await page.waitForFunction(() =>
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
457 customElements.get('mjj-composer') &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
458 customElements.get('zen-field') &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
459 customElements.get('zen-button')
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
460 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
461
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
462 const compact = page.locator('mjj-composer[compact]');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
463 const textarea = compact.locator('textarea');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
464 const submit = compact.locator('button[type="submit"]');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
465 await textarea.fill('Composer lab message');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
466 await textarea.press('Enter');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
467 await page.waitForFunction(() =>
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
468 [...document.querySelectorAll('[data-output]')]
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
469 .some(output => output.textContent.includes('Composer lab message'))
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
470 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
471
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
472 const geometry = await compact.evaluate(element => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
473 const field = element.querySelector('zen-field');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
474 const button = element.querySelector('zen-button');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
475 const nativeButton = button.querySelector('button');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
476 const buttonBox = nativeButton.getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
477 return {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
478 compactButton: Math.abs(buttonBox.width - buttonBox.height) < 1,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
479 fieldStyled: !field.hasAttribute('appearance'),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
480 oneButtonOwner: nativeButton.closest('zen-button') === button,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
481 textareaOwned: element.querySelector('textarea').closest('zen-field') === field,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
482 };
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
483 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
484 assert.deepEqual(geometry, {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
485 compactButton: true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
486 fieldStyled: true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
487 oneButtonOwner: true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
488 textareaOwned: true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
489 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
490 assert.equal(await submit.getAttribute('aria-label'), 'Send message');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
491 await context.close();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
492 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
493
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
494 async function testJrpgPage(browser) {
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
495 const context = await browser.newContext({
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
496 colorScheme: 'light',
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
497 viewport: { width: 1280, height: 900 },
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
498 });
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
499 await context.addInitScript(key => {
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
500 sessionStorage.setItem(
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
501 key,
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
502 '00000000-0000-4000-8000-000000000000',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
503 );
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
504 }, 'mjj-jrpg-conversation-id');
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
505 const page = await context.newPage();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
506 const errors = [];
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
507 page.on('pageerror', error => errors.push(`pageerror: ${error.message}`));
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
508 page.on('console', message => {
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
509 if (message.type() === 'error' &&
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
510 !message.text().startsWith('Failed to load resource:')) {
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
511 errors.push(`console: ${message.text()}`);
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
512 }
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
513 });
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
514 page.on('requestfailed', request => {
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
515 if (request.url().startsWith('blob:') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
516 request.failure()?.errorText === 'net::ERR_ABORTED') {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
517 return;
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
518 }
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
519 if (request.method() === 'DELETE' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
520 request.url().includes('/api/download/') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
521 request.failure()?.errorText === 'net::ERR_ABORTED') {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
522 return;
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
523 }
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
524 if (request.method() === 'POST' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
525 request.url().endsWith('/api/latex/render') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
526 request.failure()?.errorText === 'net::ERR_ABORTED') {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
527 return;
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
528 }
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
529 if (request.url().includes('/api/auth/login') &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
530 request.failure()?.errorText === 'net::ERR_ABORTED') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
531 return;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
532 }
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
533 errors.push(`requestfailed: ${request.url()} ${request.failure()?.errorText || ''}`);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
534 });
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
535 page.on('response', response => {
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
536 if (response.status() === 404 &&
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
537 response.url().endsWith(
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
538 '/api/conversations/00000000-0000-4000-8000-000000000000'
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
539 )) {
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
540 return;
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
541 }
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
542 if (response.url().includes('/api/auth/login') && response.status() >= 400) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
543 return; /* expected: login attempt with invalid credentials in modal test */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
544 }
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
545 if (response.status() >= 400) {
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
546 errors.push(`response: ${response.status()} ${response.url()}`);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
547 }
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
548 });
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
549
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
550 await page.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
551 await page.waitForFunction(() =>
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
552 customElements.get('mjj-composer') &&
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
553 customElements.get('mjj-jrpg-menu') &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
554 customElements.get('mjj-jrpg-chat') &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
555 customElements.get('mjj-jrpg-preview')
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
556 );
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
557 await page.evaluate(() => document.fonts.ready);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
558 const desktop = await page.evaluate(() => {
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
559 const scene = document.querySelector('.jrpg-scene').getBoundingClientRect();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
560 const utility = document.querySelector('.jrpg-utility').getBoundingClientRect();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
561 const composer = document.querySelector('mjj-composer')
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
562 .getBoundingClientRect();
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
563 const composerField = document.querySelector('.jrpg-composer zen-field')
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
564 .getBoundingClientRect();
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
565 const composerFieldStyle = getComputedStyle(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
566 document.querySelector('.jrpg-composer zen-field'),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
567 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
568 const composerLabel = document.querySelector('.jrpg-composer label')
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
569 .getBoundingClientRect();
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
570 const composerTextarea = document.querySelector('#jrpg-message')
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
571 .getBoundingClientRect();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
572 const menuElement = document.querySelector('mjj-jrpg-menu');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
573 const menu = menuElement.getBoundingClientRect();
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
574 const character = document.querySelector('[data-character]');
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
575 const epiAvatar = document.querySelector(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
576 '.jrpg-message[data-speaker="Epi"] .jrpg-message-avatar',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
577 );
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
578 const characterBox = character.getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
579 const sceneBarStyle = getComputedStyle(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
580 document.querySelector('.jrpg-scene'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
581 '::before',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
582 );
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
583 const messageScroller = document.querySelector('zen-message-scroller')
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
584 .getBoundingClientRect();
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
585 const messageViewport = document.querySelector('.jrpg-message-viewport')
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
586 .getBoundingClientRect();
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
587 const workspace = document.querySelector('.jrpg-workspace')
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
588 .getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
589 const brand = document.querySelector('.jrpg-brand').getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
590 const frameControls = document.querySelector('.jrpg-frame-controls')
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
591 .getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
592 const frameTelemetry = document.querySelector('.jrpg-frame-telemetry')
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
593 .getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
594 const telemetryValues = [
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
595 ...document.querySelectorAll('.jrpg-frame-telemetry > *'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
596 ].map(value => value.getBoundingClientRect());
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
597 const shell = document.querySelector('.jrpg-shell').getBoundingClientRect();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
598 const main = document.querySelector('.jrpg-main').getBoundingClientRect();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
599 const colorProbe = document.createElement('span');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
600 colorProbe.style.background = 'var(--zenbu-sys-color-surface-page)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
601 colorProbe.style.color =
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
602 'var(--zenbu-sys-color-action-primary-background)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
603 colorProbe.style.borderColor = 'var(--zenbu-sys-color-focus-outer)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
604 const surfaceProbe = document.createElement('span');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
605 surfaceProbe.style.background =
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
606 'var(--zenbu-sys-color-surface-default)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
607 surfaceProbe.style.color = 'var(--zenbu-sys-color-text-primary)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
608 surfaceProbe.style.borderColor = 'var(--zenbu-sys-color-border-strong)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
609 const sunkenProbe = document.createElement('span');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
610 sunkenProbe.style.background =
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
611 'var(--zenbu-sys-color-surface-sunken)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
612 const panelProbe = document.createElement('span');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
613 panelProbe.style.background = 'var(--mjj-jrpg-panel-strong)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
614 document.body.append(colorProbe, surfaceProbe, sunkenProbe, panelProbe);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
615 const probeStyle = getComputedStyle(colorProbe);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
616 const surfaceProbeStyle = getComputedStyle(surfaceProbe);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
617 const sunkenProbeStyle = getComputedStyle(sunkenProbe);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
618 const panelProbeStyle = getComputedStyle(panelProbe);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
619 const computedFonts = [
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
620 document.body,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
621 document.querySelector('.jrpg-brand h1'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
622 document.querySelector('.jrpg-message p'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
623 document.querySelector('#jrpg-message'),
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
624 document.querySelector('.jrpg-composer button[type="submit"]'),
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
625 ].map(element => getComputedStyle(element).fontFamily);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
626 const nonPixelText = [document.body, ...document.body.querySelectorAll('*')]
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
627 .filter(element => [...element.childNodes].some(node =>
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
628 node.nodeType === Node.TEXT_NODE && node.textContent.trim()
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
629 ))
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
630 .filter(element =>
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
631 getComputedStyle(element).fontFamily !== '"Pixel Mplus"'
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
632 )
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
633 .map(element => element.localName);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
634 const pageStyle = getComputedStyle(document.body);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
635 const submitStyle = getComputedStyle(
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
636 document.querySelector('.jrpg-composer button[type="submit"]'),
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
637 );
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
638 const colors = {
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
639 canvas: probeStyle.backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
640 conversation: getComputedStyle(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
641 document.querySelector('mjj-jrpg-chat'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
642 ).backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
643 conversationBorder: getComputedStyle(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
644 document.querySelector('mjj-jrpg-chat'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
645 ).borderTopColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
646 conversationPanel: panelProbeStyle.backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
647 conversationText: getComputedStyle(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
648 document.querySelector('.jrpg-message p'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
649 ).color,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
650 focus: probeStyle.borderColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
651 frame: surfaceProbeStyle.borderColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
652 menu: getComputedStyle(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
653 document.querySelector('mjj-jrpg-menu'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
654 ).backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
655 page: pageStyle.backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
656 primary: probeStyle.color,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
657 primaryText: getComputedStyle(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
658 document.querySelector('.jrpg-preview-panel h2'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
659 ).color,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
660 sunken: sunkenProbeStyle.backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
661 surface: surfaceProbeStyle.backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
662 submit: submitStyle.backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
663 text: surfaceProbeStyle.color,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
664 utility: getComputedStyle(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
665 document.querySelector('.jrpg-utility'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
666 ).backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
667 };
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
668 colorProbe.remove();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
669 surfaceProbe.remove();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
670 sunkenProbe.remove();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
671 panelProbe.remove();
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
672 const closeTo = (value, expected) => Math.abs(value - expected) < 0.01;
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
673 const frameAlignment = [
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
674 closeTo((scene.left - workspace.left) / workspace.width, 0.032),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
675 closeTo((scene.top - workspace.top) / workspace.height, 0.094),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
676 closeTo(scene.width / workspace.width, 0.548),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
677 closeTo(scene.height / workspace.height, 0.57),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
678 closeTo((utility.left - workspace.left) / workspace.width, 0.604),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
679 closeTo(utility.width / workspace.width, 0.365),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
680 closeTo((composer.top - workspace.top) / workspace.height, 0.72),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
681 closeTo(composer.width / workspace.width, 0.682),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
682 closeTo((menu.left - workspace.left) / workspace.width, 0.734),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
683 closeTo(menu.width / workspace.width, 0.234),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
684 ].every(Boolean);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
685 const borderless = [
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
686 '.jrpg-shell',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
687 '.jrpg-scene',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
688 '.jrpg-utility',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
689 'mjj-jrpg-chat',
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
690 'mjj-composer',
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
691 'mjj-jrpg-menu',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
692 '.jrpg-preview-panel',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
693 '.jrpg-message',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
694 '.jrpg-work-showcase a',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
695 'mjj-jrpg-menu button',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
696 ].every(selector => {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
697 const style = getComputedStyle(document.querySelector(selector));
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
698 return style.borderTopWidth === '0px' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
699 style.borderRightWidth === '0px' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
700 style.borderBottomWidth === '0px' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
701 style.borderLeftWidth === '0px';
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
702 });
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
703 return {
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
704 art: getComputedStyle(document.querySelector('.jrpg-workspace'))
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
705 .backgroundImage,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
706 borderless,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
707 brandInSystemSlot:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
708 closeTo((brand.left - workspace.left) / workspace.width, 0.054) &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
709 closeTo((brand.top - workspace.top) / workspace.height, 0.022) &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
710 document.querySelector('.jrpg-brand').parentElement.classList
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
711 .contains('jrpg-workspace'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
712 brandCoversSystemLabel:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
713 brand.left <= workspace.left + workspace.width * 0.062 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
714 brand.right >= workspace.left + workspace.width * 0.102 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
715 brand.top <= workspace.top + workspace.height * 0.03 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
716 brand.bottom >= workspace.top + workspace.height * 0.06,
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
717 characterLoaded: character.complete && character.naturalWidth > 0,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
718 epiAvatarLoaded:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
719 epiAvatar?.complete &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
720 epiAvatar.naturalWidth > 0 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
721 epiAvatar.getAttribute('aria-hidden') === 'true',
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
722 colors,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
723 composerBelowScene: composer.top >= scene.bottom,
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
724 composerTextareaFills: (
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
725 Math.abs(composerTextarea.left - composerField.left) < 1 &&
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
726 Math.abs(composerTextarea.right - composerField.right) < 1 &&
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
727 Math.abs(composerTextarea.bottom - composerField.bottom) < 1 &&
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
728 composerTextarea.height > 60
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
729 ),
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
730 composerUsesZenStyles:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
731 getComputedStyle(document.querySelector('.jrpg-composer textarea'))
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
732 .borderTopWidth !== '0px' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
733 submitStyle.borderTopWidth !== '0px',
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
734 composerTextareaGeometry: {
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
735 fieldBottom: composerField.bottom,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
736 fieldDisplay: composerFieldStyle.display,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
737 fieldGridRows: composerFieldStyle.gridTemplateRows,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
738 fieldLeft: composerField.left,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
739 fieldRight: composerField.right,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
740 fieldTop: composerField.top,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
741 labelBottom: composerLabel.bottom,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
742 labelTop: composerLabel.top,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
743 textareaBottom: composerTextarea.bottom,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
744 textareaHeight: composerTextarea.height,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
745 textareaLeft: composerTextarea.left,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
746 textareaRight: composerTextarea.right,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
747 textareaTop: composerTextarea.top,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
748 },
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
749 fillsViewport: shell.left === 0 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
750 shell.top === 0 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
751 Math.abs(shell.right - innerWidth) < 1 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
752 Math.abs(shell.bottom - innerHeight) < 1 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
753 main.left === 0 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
754 main.top === 0 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
755 Math.abs(main.right - innerWidth) < 1 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
756 Math.abs(main.bottom - innerHeight) < 1,
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
757 frameAlignment,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
758 frameChromeAligned:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
759 closeTo((frameControls.left - workspace.left) / workspace.width, 0.866) &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
760 closeTo((frameTelemetry.left - workspace.left) / workspace.width, 0.085) &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
761 closeTo((frameTelemetry.top - workspace.top) / workspace.height, 0.928),
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
762 fonts: computedFonts,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
763 fontLoaded: [...document.fonts].some(font =>
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
764 font.family.replaceAll('"', '') === 'Pixel Mplus' &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
765 font.status === 'loaded'
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
766 ),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
767 menuRightOfComposer: menu.left >= composer.right,
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
768 messageViewportFills: (
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
769 Math.abs(messageViewport.top - messageScroller.top) < 1 &&
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
770 Math.abs(messageViewport.bottom - messageScroller.bottom) < 1 &&
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
771 messageViewport.height > 192
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
772 ),
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
773 noOverflow: document.documentElement.scrollWidth <= innerWidth,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
774 nonPixelText,
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
775 questLabelAbsent: !document.body.textContent.includes('QUEST 01'),
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
776 previewLabelsRemoved:
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
777 !/CHARACTER RECORD|ITEM INVENTORY|QUEST ARCHIVE/.test(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
778 document.querySelector('.jrpg-preview-panel').textContent,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
779 ),
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
780 statsRemoved:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
781 !document.querySelector('.jrpg-preview-stats') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
782 !document.querySelector('[data-preview-type]'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
783 telemetryCovered:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
784 document.querySelectorAll('.jrpg-frame-telemetry > *').length === 4 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
785 document.querySelector('[data-frame-network]').textContent
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
786 .includes('ONLINE') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
787 document.querySelector('[data-frame-uptime]').textContent
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
788 .match(/^\d{2}:\d{2}:\d{2}$/) &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
789 [...document.querySelectorAll('.jrpg-frame-telemetry > *')]
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
790 .every(item => !/TEMP:|USER:|STATUS:|UPTIME:/.test(item.textContent)),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
791 telemetryValuesAligned:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
792 closeTo(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
793 (telemetryValues[0].left + telemetryValues[0].width / 2 -
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
794 frameTelemetry.left) / frameTelemetry.width,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
795 0.12,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
796 ) &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
797 closeTo(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
798 (telemetryValues[1].left + telemetryValues[1].width / 2 -
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
799 frameTelemetry.left) / frameTelemetry.width,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
800 0.325,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
801 ) &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
802 closeTo(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
803 (telemetryValues[2].left + telemetryValues[2].width / 2 -
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
804 frameTelemetry.left) / frameTelemetry.width,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
805 0.605,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
806 ) &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
807 closeTo(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
808 (telemetryValues[3].left + telemetryValues[3].width / 2 -
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
809 frameTelemetry.left) / frameTelemetry.width,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
810 0.88,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
811 ),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
812 shibaInFrontOfBar:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
813 sceneBarStyle.backgroundImage.includes('bar-ink.webp') &&
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
814 sceneBarStyle.backgroundSize === 'cover' &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
815 Math.abs(parseFloat(sceneBarStyle.height) - scene.height) < 1 &&
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
816 Number(getComputedStyle(character.parentElement).zIndex) >
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
817 Number(sceneBarStyle.zIndex) &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
818 characterBox.bottom > scene.top + scene.height * 0.65,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
819 terminalScrollbar: (
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
820 getComputedStyle(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
821 document.querySelector('.jrpg-message-viewport'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
822 ).scrollbarWidth === 'thin' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
823 getComputedStyle(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
824 document.querySelector('.jrpg-message-viewport'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
825 ).scrollbarColor !== 'auto'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
826 ),
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
827 theme: document.documentElement.dataset.zenTheme,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
828 utilityRightOfScene: utility.left >= scene.right,
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
829 workspaceFillsViewport:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
830 Math.abs(workspace.left) < 1 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
831 Math.abs(workspace.top) < 1 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
832 Math.abs(workspace.right - innerWidth) < 1 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
833 Math.abs(workspace.bottom - innerHeight) < 1,
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
834 };
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
835 });
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
836 assert.match(desktop.art, /background-frame-2\.webp/);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
837 assert.equal(desktop.borderless, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
838 assert.equal(desktop.brandInSystemSlot, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
839 assert.equal(desktop.brandCoversSystemLabel, true);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
840 assert.equal(desktop.characterLoaded, true);
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
841 assert.equal(desktop.epiAvatarLoaded, true);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
842 assert.equal(desktop.colors.page, desktop.colors.canvas);
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
843 assert.equal(desktop.colors.conversation, 'rgba(0, 0, 0, 0)');
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
844 assert.equal(desktop.colors.conversationText, desktop.colors.text);
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
845 assert.equal(desktop.colors.menu, 'rgba(0, 0, 0, 0)');
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
846 assert.equal(desktop.colors.primaryText, desktop.colors.primary);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
847 assert.equal(desktop.colors.submit, desktop.colors.primary);
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
848 assert.equal(desktop.composerUsesZenStyles, true);
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
849 assert.equal(desktop.colors.utility, 'rgba(0, 0, 0, 0)');
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
850 assert.equal(desktop.composerBelowScene, true);
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
851 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
852 desktop.composerTextareaFills,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
853 true,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
854 JSON.stringify(desktop.composerTextareaGeometry),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
855 );
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
856 assert.equal(desktop.fillsViewport, true);
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
857 assert.equal(desktop.frameAlignment, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
858 assert.equal(desktop.frameChromeAligned, true);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
859 assert.ok(desktop.fonts.every(font => font === '"Pixel Mplus"'));
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
860 assert.equal(desktop.fontLoaded, true);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
861 assert.equal(desktop.menuRightOfComposer, true);
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
862 assert.equal(desktop.messageViewportFills, true);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
863 assert.equal(desktop.noOverflow, true);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
864 assert.deepEqual(desktop.nonPixelText, []);
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
865 assert.equal(desktop.questLabelAbsent, true);
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
866 assert.equal(desktop.previewLabelsRemoved, true);
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
867 assert.equal(desktop.statsRemoved, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
868 assert.equal(desktop.telemetryCovered, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
869 assert.equal(desktop.telemetryValuesAligned, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
870 assert.equal(desktop.shibaInFrontOfBar, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
871 assert.equal(desktop.terminalScrollbar, true);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
872 assert.equal(desktop.theme, 'cyberpunk');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
873 assert.equal(desktop.utilityRightOfScene, true);
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
874 assert.equal(desktop.workspaceFillsViewport, true);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
875 await page.locator('.jrpg-brand a').focus();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
876 assert.equal(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
877 await page.locator('.jrpg-brand a').evaluate(element =>
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
878 getComputedStyle(element).outlineColor
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
879 ),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
880 desktop.colors.focus,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
881 );
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
882 await page.locator('.jrpg-composer button[type="submit"]').focus();
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
883 assert.equal(
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
884 await page.locator('.jrpg-composer button[type="submit"]').evaluate(element =>
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
885 getComputedStyle(element).outlineColor
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
886 ),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
887 desktop.colors.focus,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
888 );
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
889 assert.equal(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
890 await page.locator('meta[name="theme-color"]').first().getAttribute('content'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
891 desktop.colors.canvas,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
892 );
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
893 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
894 await page.locator('.jrpg-frame-controls :is(button, a)').count(),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
895 3,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
896 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
897 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
898 await page.locator('.jrpg-frame-controls a').getAttribute('href'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
899 '/',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
900 );
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
901
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
902 // Account slot: guest session shows a login button (modal trigger)
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
903 assert.ok(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
904 await page.locator('[data-frame-account]').count() > 0,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
905 'account slot exists in telemetry',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
906 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
907 await page.waitForFunction(() =>
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
908 document.querySelector('[data-frame-account]')?.querySelector('button[data-login-open]') !== null
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
909 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
910 const loginBtnState = await page.locator('[data-frame-account] button[data-login-open]').evaluate(btn => ({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
911 text: btn.textContent.trim(),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
912 ownerCount: btn.closest('zen-button') ? 1 : 0,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
913 appearance: btn.closest('zen-button')?.getAttribute('appearance'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
914 size: btn.closest('zen-button')?.getAttribute('size'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
915 }));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
916 assert.match(loginBtnState.text, /LOGIN/i);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
917 assert.equal(loginBtnState.ownerCount, 1, 'login button has zen-button owner');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
918 assert.equal(loginBtnState.appearance, 'plain');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
919 assert.equal(loginBtnState.size, 'xs');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
920
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
921 // Login modal: opens on button click, focuses username, closes on cancel
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
922 await page.locator('[data-frame-account] button[data-login-open]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
923 await page.locator('[data-login-dialog]').waitFor({ state: 'visible' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
924 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
925 await page.locator('[data-login-dialog]').getAttribute('aria-modal'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
926 'true',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
927 'login dialog is modal',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
928 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
929 // Username input should receive initial focus
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
930 await page.waitForFunction(() => document.activeElement?.id === 'jrpg-login-username');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
931 // Cancel closes dialog and clears password
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
932 await page.locator('#jrpg-login-password').fill('dummypassword');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
933 await page.locator('[data-login-cancel]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
934 await page.locator('[data-login-dialog]').waitFor({ state: 'hidden' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
935 await page.waitForFunction(() => !document.querySelector('#jrpg-login-password')?.value);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
936 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
937 await page.locator('#jrpg-login-password').inputValue(),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
938 '',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
939 'password cleared on close',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
940 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
941
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
942 // Invalid credentials show error message
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
943 await page.locator('[data-frame-account] button[data-login-open]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
944 await page.locator('[data-login-dialog]').waitFor({ state: 'visible' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
945 await page.locator('#jrpg-login-username').fill('nosuchuser');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
946 await page.locator('#jrpg-login-password').fill('nosuchpassword123');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
947 let loginErrorShown = false;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
948 const loginResponsePromise = page.waitForResponse(resp =>
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
949 resp.url().includes('/api/auth/login')
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
950 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
951 await page.locator('[data-login-submit]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
952 const loginResp = await loginResponsePromise;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
953 if (loginResp.status() >= 400) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
954 await page.waitForFunction(() => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
955 const el = document.querySelector('[data-login-error]');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
956 return el && !el.hidden && el.textContent.trim().length > 0;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
957 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
958 loginErrorShown = true;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
959 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
960 assert.equal(loginErrorShown, true, 'error element shown on bad credentials');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
961 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
962 await page.locator('#jrpg-login-password').inputValue(),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
963 '',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
964 'password cleared after failed login attempt',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
965 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
966 // Close modal via X button (data-zen-close)
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
967 await page.getByRole('button', { name: 'Close sign-in dialog' }).click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
968 await page.locator('[data-login-dialog]').waitFor({ state: 'hidden' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
969
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
970 // Archive opens only from the bottom destination menu.
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
971 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
972 await page.locator('[data-toggle-archive]').count(),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
973 0,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
974 'redundant chat-heading archive shortcut is removed',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
975 );
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
976 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
977 await page.locator('.jrpg-panel-heading').count(),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
978 0,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
979 'visible conversation heading is removed',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
980 );
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
981 await page.locator('button[data-preview="conversations"]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
982 await page.locator('.jrpg-utility mjj-conversation-archive').waitFor({ state: 'visible' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
983 const archiveGeometry = await page.evaluate(() => {
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
984 const utilityElement = document.querySelector('.jrpg-utility');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
985 const archiveElement = utilityElement.querySelector('mjj-conversation-archive');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
986 const utility = utilityElement.getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
987 const archive = archiveElement.getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
988 const archiveStyle = getComputedStyle(archiveElement);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
989 const previewPanel = utilityElement.querySelector('.jrpg-preview-panel');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
990 const panel = previewPanel.getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
991 const previewPanelStyle = getComputedStyle(previewPanel);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
992 const panelPadding = {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
993 bottom: parseFloat(previewPanelStyle.paddingBottom),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
994 left: parseFloat(previewPanelStyle.paddingLeft),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
995 right: parseFloat(previewPanelStyle.paddingRight),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
996 top: parseFloat(previewPanelStyle.paddingTop),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
997 };
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
998 const previewContent = previewPanel.querySelector('[data-preview-content]');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
999 const renderedPanelChildren = Array.from(previewPanel.children)
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1000 .filter(element => getComputedStyle(element).display !== 'none')
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1001 .map(element => element.localName);
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1002 return {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1003 archive: {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1004 bottom: archive.bottom,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1005 height: archive.height,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1006 left: archive.left,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1007 right: archive.right,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1008 top: archive.top,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1009 width: archive.width,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1010 },
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1011 fits: Math.abs(archive.left - panel.left - panelPadding.left) < 1 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1012 Math.abs(archive.top - panel.top - panelPadding.top) < 1 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1013 Math.abs(panel.right - panelPadding.right - archive.right) < 1 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1014 Math.abs(panel.bottom - panelPadding.bottom - archive.bottom) < 1,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1015 integrated: archiveStyle.position === 'static' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1016 archiveStyle.zIndex === 'auto' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1017 archiveStyle.backgroundColor === 'rgba(0, 0, 0, 0)' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1018 archiveStyle.backgroundImage === 'none' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1019 archiveStyle.boxShadow === 'none' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1020 previewPanelStyle.display === 'block' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1021 archiveElement.parentElement === previewPanel &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1022 previewContent.hidden &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1023 renderedPanelChildren.length === 1 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1024 renderedPanelChildren[0] === 'mjj-conversation-archive',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1025 renderedPanelChildren,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1026 panel: {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1027 bottom: panel.bottom,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1028 height: panel.height,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1029 left: panel.left,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1030 right: panel.right,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1031 top: panel.top,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1032 width: panel.width,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1033 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1034 panelPadding,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1035 utility: {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1036 bottom: utility.bottom,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1037 height: utility.height,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1038 left: utility.left,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1039 right: utility.right,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1040 top: utility.top,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1041 width: utility.width,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1042 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1043 };
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1044 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1045 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1046 archiveGeometry.fits,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1047 true,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1048 `conversation archive fills the existing utility content panel: ${JSON.stringify(archiveGeometry)}`,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1049 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1050 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1051 archiveGeometry.integrated,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1052 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1053 `conversation archive renders as utility content instead of an overlay: ${JSON.stringify(archiveGeometry)}`,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1054 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1055 // Archive status or empty message should be visible
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1056 await page.waitForFunction(() => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1057 const status = document.querySelector('[data-archive-status]');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1058 return status && !status.hidden;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1059 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1060 // New conversation button exists inside archive
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1061 assert.ok(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1062 await page.locator('[data-archive-new]').isVisible(),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1063 'archive new button visible',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1064 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1065 // Conversations menu button should be pressed
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1066 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1067 await page.locator('button[data-preview="conversations"]').getAttribute('aria-pressed'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1068 'true',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1069 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1070
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1071 // Archive: close via close button, navigates back to resume panel
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1072 await page.locator('[data-archive-close]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1073 await page.locator('.jrpg-utility mjj-conversation-archive').waitFor({ state: 'hidden' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1074 // mjj-jrpg-chat must remain visible (always in scene)
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1075 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1076 await page.locator('mjj-jrpg-chat').isVisible(),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1077 true,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1078 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1079
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1080 // Quota element is present (may be shown for guest session)
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1081 assert.ok(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1082 await page.locator('[data-quota]').count() > 0,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1083 'quota element exists',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1084 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1085
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1086 await page.getByRole('button', { name: 'Minimize interface' }).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1087 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1088 await page.locator('.jrpg-scene').evaluate(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1089 scene => getComputedStyle(scene).visibility,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1090 ),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1091 'hidden',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1092 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1093 await page.getByRole('button', { name: 'Restore interface' }).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1094 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1095 await page.locator('.jrpg-scene').evaluate(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1096 scene => getComputedStyle(scene).visibility,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1097 ),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1098 'visible',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1099 );
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1100 assert.equal(await page.locator('[data-work-showcase] a').count(), 8);
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1101 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1102 await page.getByRole('button', { name: /Inspect/ }).count(),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1103 0,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1104 );
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1105 assert.match(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1106 await page.locator('[data-work-showcase]').textContent(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1107 /Copilot Tasks/,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1108 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1109 assert.match(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1110 await page.locator('[data-work-showcase]').textContent(),
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1111 /AIX Harness \/ Copilot/,
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1112 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1113 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1114 await page.locator('[data-turn-position]').textContent(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1115 'START',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1116 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1117 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1118 await page.getByRole('button', { name: 'Previous turn' }).isDisabled(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1119 true,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1120 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1121 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1122 await page.getByRole('button', { name: 'Next turn' }).isDisabled(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1123 true,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1124 );
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1125
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1126 await page.getByRole('button', { name: 'Tools', exact: true }).click();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1127 assert.equal(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1128 await page.locator('[data-preview-title]').textContent(),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1129 'Tools',
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1130 );
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1131 assert.equal(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1132 await page.locator('[data-preview-link]').getAttribute('href'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1133 '/tools',
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1134 );
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1135 assert.equal(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1136 await page.getByRole('button', { name: 'Tools', exact: true })
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1137 .getAttribute('aria-pressed'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1138 'true',
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1139 );
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1140 await page.waitForFunction(() =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1141 document.querySelectorAll('[data-latest-tool]').length === 5
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1142 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1143 assert.match(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1144 await page.locator('[data-work-showcase]').textContent(),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1145 /Online LaTeX Editor/,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1146 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1147 assert.match(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1148 await page.locator('[data-work-showcase]').textContent(),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1149 /Personal Notes/,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1150 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1151 await page.locator('[data-latest-tool]').first().click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1152 await page.locator('[data-functional-tool="markdown"]').waitFor();
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1153 assert.equal(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1154 await page.locator('[data-dialog-title]').textContent(),
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1155 'MarkDown to HTML',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1156 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1157 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1158 await page.locator('[data-preview-link]').getAttribute('href'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1159 '/tools/markdown_to_html',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1160 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1161 await page.locator('[data-markdown-source]').fill('# Modal Markdown');
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1162 await page.waitForFunction(() =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1163 document.querySelector('[data-markdown-output] h1')?.textContent ===
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1164 'Modal Markdown'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1165 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1166 assert.equal(await page.locator('.jrpg-tool-pane').count(), 2);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1167 const toolWorkspace = await page.evaluate(() => {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1168 const dialogElement = document.querySelector(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1169 '.jrpg-detail-dialog[data-detail-mode="tools"]',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1170 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1171 const dialog = dialogElement.getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1172 const windows = [...document.querySelectorAll('.jrpg-tool-window')]
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1173 .map(window => window.getBoundingClientRect());
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1174 const windowShadows = [...document.querySelectorAll('.jrpg-tool-window')]
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1175 .map(window => getComputedStyle(window).boxShadow);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1176 const rail = getComputedStyle(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1177 document.querySelector('.jrpg-tool-panes'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1178 '::before',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1179 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1180 return {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1181 dialogHeight: dialogElement.offsetHeight,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1182 dialogWidth: dialogElement.offsetWidth,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1183 fillsViewport: dialogElement.offsetWidth > innerWidth * 0.9 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1184 dialogElement.offsetHeight > innerHeight * 0.9,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1185 viewportHeight: innerHeight,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1186 viewportWidth: innerWidth,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1187 sideBySide: windows.length === 2 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1188 windows[0].right < windows[1].left &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1189 Math.abs(windows[0].top - windows[1].top) < 1,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1190 fullPageInHeader: Boolean(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1191 document.querySelector('[data-preview-link]')
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1192 .closest('.jrpg-dialog-heading-actions'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1193 ),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1194 footerHidden: document.querySelector('[data-dialog-actions]').hidden,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1195 metalRail: rail.content !== 'none' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1196 rail.backgroundImage.includes('bar-ink.webp'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1197 pixelIcons: document.querySelectorAll('.jrpg-tool-window zen-icon').length >= 2 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1198 [...document.querySelectorAll('.jrpg-tool-window zen-icon svg')]
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1199 .every(icon =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1200 getComputedStyle(icon).shapeRendering.toLowerCase() === 'crispedges'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1201 ),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1202 separateGlows: windowShadows.length === 2 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1203 windowShadows.every(shadow => shadow !== 'none'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1204 wideWindows: windows.every(window => window.width > dialog.width * 0.35),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1205 };
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1206 });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1207 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1208 toolWorkspace.fillsViewport,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1209 true,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1210 JSON.stringify(toolWorkspace),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1211 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1212 assert.equal(toolWorkspace.sideBySide, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1213 assert.equal(toolWorkspace.fullPageInHeader, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1214 assert.equal(toolWorkspace.footerHidden, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1215 assert.equal(toolWorkspace.metalRail, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1216 assert.equal(toolWorkspace.pixelIcons, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1217 assert.equal(toolWorkspace.separateGlows, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1218 assert.equal(toolWorkspace.wideWindows, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1219 await page.getByRole('button', {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1220 name: 'Close destination details',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1221 }).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1222 await page.locator('.jrpg-preview-dialog dialog').waitFor({ state: 'hidden' });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1223
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1224 await page.locator('[data-latest-tool]').first().click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1225 await page.locator('[data-functional-tool="markdown"]').waitFor();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1226 await page.getByRole('button', {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1227 name: 'Close destination details',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1228 }).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1229 await page.locator('.jrpg-preview-dialog dialog').waitFor({ state: 'hidden' });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1230
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1231 await page.locator('[data-latest-tool]').nth(1).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1232 await page.locator('[data-functional-tool="converter"]').waitFor();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1233 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1234 await page.locator('[data-converter-input]').count(),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1235 2,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1236 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1237 const converterFixture = path.join(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1238 RUNFILES,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1239 WORKSPACE,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1240 'mrjunejune/test/shiba.webp',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1241 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1242 assert.equal(fs.existsSync(converterFixture), true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1243 await page.locator('[data-converter-input="image"]').setInputFiles(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1244 converterFixture,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1245 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1246 const conversionResponse = page.waitForResponse(response =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1247 response.url().endsWith('/api/convert/image-to-webp') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1248 response.request().method() === 'POST'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1249 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1250 await page.locator('[data-convert-kind="image"]').click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1251 assert.equal((await conversionResponse).status(), 200);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1252 await page.locator('[data-converter-download="image"]').waitFor();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1253 const cleanupResponse = page.waitForResponse(response =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1254 response.url().includes('/api/download/') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1255 response.request().method() === 'DELETE'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1256 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1257 await page.getByRole('button', {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1258 name: 'Close destination details',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1259 }).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1260 assert.equal((await cleanupResponse).status(), 204);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1261 await page.locator('.jrpg-preview-dialog dialog').waitFor({ state: 'hidden' });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1262
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1263 await page.locator('[data-latest-tool]').nth(1).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1264 await page.locator('[data-functional-tool="converter"]').waitFor();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1265 await page.locator('[data-converter-input="image"]').setInputFiles(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1266 converterFixture,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1267 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1268 const lateConversionResponse = page.waitForResponse(response =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1269 response.url().endsWith('/api/convert/image-to-webp') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1270 response.request().method() === 'POST'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1271 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1272 const lateCleanupResponse = page.waitForResponse(response =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1273 response.url().includes('/api/download/') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1274 response.request().method() === 'DELETE'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1275 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1276 await page.locator('[data-convert-kind="image"]').click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1277 await page.getByRole('button', {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1278 name: 'Close destination details',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1279 }).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1280 assert.equal((await lateConversionResponse).status(), 200);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1281 assert.equal((await lateCleanupResponse).status(), 204);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1282 await page.locator('.jrpg-preview-dialog dialog').waitFor({ state: 'hidden' });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1283
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1284 await page.locator('[data-latest-tool]').nth(2).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1285 await page.locator('[data-functional-tool="hls"]').waitFor();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1286 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1287 await page.locator('[data-preview-link]').getAttribute('href'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1288 '/tools/hls_player',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1289 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1290 await page.locator('[data-hls-sample]').click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1291 await page.waitForFunction(() =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1292 ['ready', 'error'].includes(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1293 document.querySelector('[data-hls-status]')?.dataset.state,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1294 )
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1295 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1296 assert.ok(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1297 ['ready', 'error'].includes(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1298 await page.locator('[data-hls-status]').getAttribute('data-state'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1299 ),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1300 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1301 assert.match(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1302 await page.locator('[data-hls-status]').textContent(),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1303 /ready|unsupported|failed/i,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1304 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1305 await page.getByRole('button', {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1306 name: 'Close destination details',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1307 }).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1308 await page.locator('.jrpg-preview-dialog dialog').waitFor({ state: 'hidden' });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1309
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1310 await page.locator('[data-latest-tool]').nth(3).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1311 await page.locator('[data-functional-tool="latex"]').waitFor();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1312 await page.locator('[data-latex-compile]').click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1313 await page.locator('[data-latex-source]').fill(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1314 '\\documentclass{article}\\begin{document}Updated modal PDF\\end{document}',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1315 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1316 assert.equal(await page.locator('[data-latex-download]').isHidden(), true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1317 await page.locator('[data-latex-compile]').click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1318 await page.waitForFunction(() =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1319 document.querySelector('[data-latex-status]')?.dataset.state === 'ready'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1320 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1321 assert.match(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1322 await page.locator('[data-latex-preview]').getAttribute('src'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1323 /^blob:/,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1324 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1325 await page.getByRole('button', {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1326 name: 'Close destination details',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1327 }).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1328 await page.locator('.jrpg-preview-dialog dialog').waitFor({ state: 'hidden' });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1329
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1330 await page.locator('[data-latest-tool]').nth(4).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1331 await page.waitForFunction(() =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1332 document.querySelector('[data-tool-content] h1')?.textContent ===
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1333 'Personal Notes'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1334 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1335 assert.match(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1336 await page.locator('[data-tool-content]').textContent(),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1337 /private browser-based writing workspace/,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1338 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1339 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1340 await page.locator('[data-preview-link]').getAttribute('href'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1341 '/notes',
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1342 );
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1343 await page.getByRole('button', {
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1344 name: 'Close destination details',
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1345 }).click();
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1346 await page.locator('.jrpg-preview-dialog dialog').waitFor({ state: 'hidden' });
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1347
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1348 await page.getByRole('button', { name: 'Resume', exact: true }).click();
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1349 await page.locator('[data-resume-modal]').click();
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1350 await page.locator('[data-resume-content] .sub-header').first().waitFor();
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1351 const resumeDossier = await page.locator('[data-resume-dossier]').evaluate(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1352 dossier => ({
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1353 fontFamily: getComputedStyle(dossier).fontFamily,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1354 text: dossier.textContent,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1355 }),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1356 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1357 assert.equal(resumeDossier.fontFamily, '"Pixel Mplus"');
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1358 assert.match(resumeDossier.text, /Copilot Tasks/);
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1359 assert.match(resumeDossier.text, /Microsoft/);
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1360 assert.match(resumeDossier.text, /Meta/);
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1361 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1362 await page.locator('[data-resume-content] a[target="_blank"]').count() > 0,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1363 true,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1364 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1365 await page.getByRole('button', {
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1366 name: 'Close destination details',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1367 }).click();
262
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1368 await page.locator('.jrpg-preview-dialog dialog').waitFor({ state: 'hidden' });
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1369
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1370 await page.getByRole('button', { name: 'Blogs', exact: true }).click();
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1371 await page.waitForFunction(() =>
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1372 document.querySelectorAll('[data-latest-blog]').length === 4
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1373 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1374 assert.match(
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1375 await page.locator('[data-work-showcase]').textContent(),
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1376 /Websocket Demystified/,
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1377 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1378 assert.match(
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1379 await page.locator('[data-work-showcase]').textContent(),
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1380 /Creating Network Library in C/,
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1381 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1382 await page.locator('[data-latest-blog]').first().click();
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1383 await page.locator('[data-blog-content] h1').waitFor();
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1384 assert.equal(
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1385 await page.locator('[data-blog-content] h1').textContent(),
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1386 'WebSocket Demystified',
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1387 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1388 assert.equal(
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1389 await page.locator('[data-preview-link]').getAttribute('href'),
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1390 '/blog/websocket-demystified',
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1391 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1392 assert.equal(
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1393 await page.locator('[data-blog-content]').evaluate(
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1394 article => getComputedStyle(article).fontFamily,
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1395 ),
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1396 '"Pixel Mplus"',
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1397 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1398 await page.getByRole('button', {
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1399 name: 'Close destination details',
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1400 }).click();
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1401 await page.locator('.jrpg-preview-dialog dialog').waitFor({ state: 'hidden' });
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1402
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1403 await page.locator('[data-blog-archive]').click();
262
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1404 await page.waitForFunction(() =>
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1405 document.querySelectorAll('[data-blog-entry]').length === 9
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1406 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1407 assert.equal(await page.locator('[data-blog-entry]').count(), 9);
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1408 await page.locator('[data-blog-entry]').nth(1).click();
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1409 await page.waitForFunction(() =>
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1410 document.querySelector('[data-blog-content] h1')?.textContent ===
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1411 'Creating Network Library in C'
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1412 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1413 assert.equal(
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1414 await page.locator('[data-preview-link]').getAttribute('href'),
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1415 '/blog/my-seobeo-journey',
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1416 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1417 await page.getByRole('button', {
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1418 name: 'Close destination details',
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1419 }).click();
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1420
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1421 await page.evaluate(() => {
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1422 window.__jrpgStreamEvents = [];
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1423 document.querySelector('mjj-jrpg-shell').addEventListener(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1424 'mjj-jrpg-stream-event',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1425 event => window.__jrpgStreamEvents.push(event.detail),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1426 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1427 });
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1428 await page.locator('#jrpg-message').fill('Where should I begin?');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1429 await page.locator('#jrpg-message').press('Enter');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1430 await page.locator('.jrpg-message[data-speaker="June"]').last().waitFor();
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1431 const streamingMessage = page.locator(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1432 '.jrpg-message[data-speaker="Epi"][data-streaming="true"]',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1433 ).last();
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1434 await streamingMessage.waitFor();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1435 await page.locator('[data-composer-cancel-owner]').waitFor({ state: 'hidden' });
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1436 await streamingMessage.waitFor();
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1437 assert.notEqual(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1438 await streamingMessage.locator('p').textContent(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1439 'hello traveler',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1440 );
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1441 await page.getByRole('button', { name: 'Blogs', exact: true }).click();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1442 assert.equal(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1443 await page.locator('.jrpg-message[data-speaker="June"] p').last()
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1444 .textContent(),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1445 'Where should I begin?',
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1446 );
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1447 await page.waitForFunction(() =>
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1448 document.querySelector('mjj-jrpg-character')?.getAttribute('state') ===
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1449 'default' &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1450 document.querySelectorAll('.jrpg-message[data-speaker="Epi"]').length > 1
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1451 );
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1452 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1453 await page.locator('.jrpg-message[data-speaker="Epi"] p').last()
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1454 .textContent(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1455 'hello traveler',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1456 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1457 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1458 await page.locator(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1459 '.jrpg-message[data-speaker="Epi"][data-streaming="true"]',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1460 ).count(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1461 0,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1462 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1463 assert.deepEqual(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1464 await page.evaluate(() => {
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1465 const event = window.__jrpgStreamEvents.find(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1466 item => item.type === 'tool.started',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1467 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1468 return {
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1469 name: event?.data.tool?.name,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1470 type: event?.type,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1471 };
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1472 }),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1473 {
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1474 name: 'mock-search',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1475 type: 'tool.started',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1476 },
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1477 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1478 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1479 await page.locator('[data-turn-position]').textContent(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1480 'TURN 1 / 1',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1481 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1482 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1483 await page.getByRole('button', { name: 'Previous turn' }).isEnabled(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1484 true,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1485 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1486 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1487 await page.getByRole('button', { name: 'Next turn' }).isDisabled(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1488 true,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1489 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1490 await page.getByRole('button', { name: 'Previous turn' }).click();
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1491 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1492 await page.locator('[data-turn-position]').textContent(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1493 'START',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1494 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1495 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1496 await page.locator('.jrpg-message[data-speaker="June"]:visible').count(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1497 0,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1498 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1499 assert.equal(
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1500 await page.locator('.jrpg-message[data-speaker="Epi"]:visible').count(),
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1501 1,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1502 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1503 await page.getByRole('button', { name: 'Next turn' }).click();
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1504 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1505 await page.locator('[data-turn-position]').textContent(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1506 'TURN 1 / 1',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1507 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1508 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1509 await page.locator('.jrpg-message[data-speaker="June"]:visible').count(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1510 1,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1511 );
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1512 assert.equal(await page.locator('#jrpg-message').isEnabled(), true);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1513
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1514 await page.waitForFunction(() => navigator.serviceWorker?.controller);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1515 await page.reload({ waitUntil: 'networkidle' });
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1516 await page.evaluate(() => document.fonts.ready);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1517 const controlledReload = await page.evaluate(() => {
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1518 const shell = document.querySelector('.jrpg-shell').getBoundingClientRect();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1519 return {
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1520 art: getComputedStyle(document.querySelector('.jrpg-workspace'))
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1521 .backgroundImage,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1522 fillsViewport: shell.left === 0 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1523 shell.top === 0 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1524 Math.abs(shell.right - innerWidth) < 1 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1525 Math.abs(shell.bottom - innerHeight) < 1,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1526 fontLoaded: document.fonts.check('16px "Pixel Mplus"'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1527 fontFamily: getComputedStyle(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1528 document.querySelector('.jrpg-brand h1'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1529 ).fontFamily,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1530 theme: document.documentElement.dataset.zenTheme,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1531 };
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1532 });
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1533 assert.match(controlledReload.art, /background-frame-2\.webp/);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1534 assert.equal(controlledReload.fillsViewport, true);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1535 assert.equal(controlledReload.fontLoaded, true);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1536 assert.equal(controlledReload.fontFamily, '"Pixel Mplus"');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1537 assert.equal(controlledReload.theme, 'cyberpunk');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1538 assert.deepEqual(errors, []);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1539 await context.close();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1540
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1541 const mobileContext = await browser.newContext({
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1542 colorScheme: 'light',
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1543 viewport: { width: 360, height: 640 },
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1544 });
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1545 const mobilePage = await mobileContext.newPage();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1546 await mobilePage.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1547 await mobilePage.waitForFunction(() =>
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1548 customElements.get('mjj-composer') &&
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1549 customElements.get('mjj-jrpg-menu')
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1550 );
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1551 const mobile = await mobilePage.evaluate(() => {
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1552 const workspace = document.querySelector('.jrpg-workspace')
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1553 .getBoundingClientRect();
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1554 const scene = document.querySelector('.jrpg-scene').getBoundingClientRect();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1555 const utility = document.querySelector('.jrpg-utility').getBoundingClientRect();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1556 const composer = document.querySelector('mjj-composer')
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1557 .getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1558 const brand = document.querySelector('.jrpg-brand').getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1559 const brandLink = document.querySelector('.jrpg-brand a').getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1560 const turnNavigation = document.querySelector('.jrpg-turn-navigation');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1561 const previousTurn = turnNavigation.querySelector('[data-turn-previous]')
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1562 .getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1563 const turnPosition = turnNavigation.querySelector('[data-turn-position]')
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1564 .getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1565 const nextTurn = turnNavigation.querySelector('[data-turn-next]')
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1566 .getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1567 const composerForm = document.querySelector('.jrpg-composer')
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1568 .getBoundingClientRect();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1569 const composerTextarea = document.querySelector('#jrpg-message')
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1570 .getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1571 const sendButton = document.querySelector(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1572 '.jrpg-composer button[type="submit"]',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1573 ).getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1574 const sendOwner = document.querySelector(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1575 '.jrpg-composer zen-button:has(button[type="submit"])',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1576 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1577 const composerField = document.querySelector(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1578 '.jrpg-composer [data-composer-control] > zen-field',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1579 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1580 const composerLabel = composerField.querySelector('label');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1581 const sendLabel = document.querySelector('[data-composer-action-label]');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1582 const menuElement = document.querySelector('mjj-jrpg-menu');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1583 const menu = menuElement.getBoundingClientRect();
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1584 const shell = document.querySelector('.jrpg-shell').getBoundingClientRect();
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1585 const hamburger = document.querySelector('[data-mobile-menu-toggle]');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1586 const hamburgerBox = hamburger?.getBoundingClientRect();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1587 const dialog = document.querySelector('[data-mobile-destination-dialog]');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1588 const destinationContent = document.querySelector(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1589 '[data-mobile-destination-content]',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1590 );
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1591 const closeTo = (value, expected, tol = 0.025) =>
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1592 Math.abs(value - expected) < tol;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1593 const wsW = workspace.width;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1594 const wsH = workspace.height;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1595 const mobileArt = getComputedStyle(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1596 document.querySelector('.jrpg-workspace'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1597 ).backgroundImage;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1598 const mobileArtIsCorrect = mobileArt.includes('background-frame-mobile.webp');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1599 const aperturesTolerance = [
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1600 closeTo((scene.left - workspace.left) / wsW, 0.048),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1601 closeTo((scene.top - workspace.top) / wsH, 0.073),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1602 closeTo(scene.width / wsW, 0.904),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1603 closeTo(scene.height / wsH, 0.712),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1604 closeTo((composer.left - workspace.left) / wsW, 0.048),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1605 closeTo((composer.top - workspace.top) / wsH, 0.796),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1606 closeTo(composer.width / wsW, 0.904),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1607 closeTo(composer.height / wsH, 0.177),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1608 closeTo((hamburgerBox.left - workspace.left) / wsW, 0.872),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1609 closeTo((hamburgerBox.top - workspace.top) / wsH, 0.013),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1610 closeTo(hamburgerBox.width / wsW, 0.094),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1611 closeTo(hamburgerBox.height / wsH, 0.053),
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1612 ].every(Boolean);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1613 const hamburgerPresent = hamburger !== null &&
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1614 hamburger.getAttribute('aria-expanded') === 'false' &&
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1615 hamburgerBox !== null &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1616 hamburgerBox.width > 0 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1617 hamburgerBox.height > 0;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1618 const composerVisible = composer.width > 0 && composer.height > 0;
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1619 return {
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1620 aperturesTolerance,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1621 brandAligned:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1622 closeTo((brand.top - workspace.top) / wsH, 0.013) &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1623 closeTo(brand.height / wsH, 0.053) &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1624 Math.abs(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1625 brandLink.left + brandLink.width / 2 -
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1626 (workspace.left + workspace.width / 2)
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1627 ) < 2,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1628 brandVisible:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1629 getComputedStyle(document.querySelector('.jrpg-brand')).display ===
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1630 'grid' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1631 document.querySelector('.jrpg-brand').textContent.includes('MrJuneJune'),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1632 composerContentAligned:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1633 composerForm.left >= composer.left &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1634 composerForm.top >= composer.top &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1635 composer.right - composerForm.right <= 8 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1636 composer.bottom - composerForm.bottom <= 8 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1637 composerForm.left - composer.left <= 8 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1638 composerForm.top - composer.top <= 8 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1639 sendButton.bottom < composerTextarea.bottom &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1640 composerTextarea.bottom - sendButton.bottom <= 16,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1641 composerGeometry: {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1642 composer: {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1643 bottom: composer.bottom,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1644 left: composer.left,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1645 right: composer.right,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1646 top: composer.top,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1647 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1648 form: {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1649 bottom: composerForm.bottom,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1650 left: composerForm.left,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1651 right: composerForm.right,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1652 top: composerForm.top,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1653 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1654 send: {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1655 bottom: sendButton.bottom,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1656 left: sendButton.left,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1657 right: sendButton.right,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1658 top: sendButton.top,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1659 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1660 textarea: {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1661 bottom: composerTextarea.bottom,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1662 left: composerTextarea.left,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1663 right: composerTextarea.right,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1664 top: composerTextarea.top,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1665 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1666 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1667 composerFieldUsesSpace:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1668 composerTextarea.left === composerForm.left &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1669 composerTextarea.right === composerForm.right &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1670 sendButton.left > composerTextarea.left &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1671 sendButton.right < composerTextarea.right &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1672 sendButton.top > composerTextarea.top &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1673 sendButton.bottom < composerTextarea.bottom,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1674 composerLabelHidden:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1675 composerLabel.getBoundingClientRect().width <= 1 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1676 composerLabel.getBoundingClientRect().height <= 1,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1677 composerVisible,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1678 dialogClosed: !dialog.open,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1679 fillsViewport: shell.left === 0 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1680 shell.top === 0 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1681 Math.abs(shell.right - innerWidth) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1682 Math.abs(shell.bottom - innerHeight) < 1,
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1683 fillsWidth: shell.left === 0 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1684 Math.abs(shell.right - innerWidth) < 1,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1685 hamburgerPresent,
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1686 initialScroll: scrollY,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1687 mediaMatches: matchMedia(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1688 '(max-width: 52rem) and (orientation: portrait)',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1689 ).matches,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1690 menuInModal: menuElement.parentElement === destinationContent,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1691 menuHidden: menu.width === 0 && menu.height === 0,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1692 mobileArtIsCorrect,
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1693 noOverflow: document.documentElement.scrollWidth <= innerWidth,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1694 sendButtonCompact:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1695 Math.abs(sendButton.width - sendButton.height) < 1 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1696 sendButton.width <= 44 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1697 getComputedStyle(sendLabel).display === 'none',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1698 telemetryHidden: getComputedStyle(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1699 document.querySelector('.jrpg-frame-telemetry'),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1700 ).display === 'none',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1701 turnNavigationAligned:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1702 Math.abs(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1703 turnPosition.left + turnPosition.width / 2 -
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1704 (workspace.left + workspace.width / 2)
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1705 ) < 2 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1706 Math.abs(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1707 previousTurn.top + previousTurn.height / 2 -
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1708 (nextTurn.top + nextTurn.height / 2)
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1709 ) < 1 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1710 previousTurn.left < turnPosition.left &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1711 nextTurn.right > turnPosition.right,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1712 turnNavigationGeometry: {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1713 nextCenter: nextTurn.left + nextTurn.width / 2,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1714 positionCenter: turnPosition.left + turnPosition.width / 2,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1715 previousCenter: previousTurn.left + previousTurn.width / 2,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1716 workspaceCenter: workspace.left + workspace.width / 2,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1717 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1718 topLeftClear: document.elementFromPoint(10, 10)?.classList
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1719 .contains('jrpg-workspace'),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1720 utilityHidden: utility.width === 0 && utility.height === 0,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1721 utilityInModal: document.querySelector('.jrpg-utility').parentElement ===
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1722 destinationContent,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1723 usesDesignSystemControls:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1724 !composerField.hasAttribute('appearance') &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1725 !sendOwner.hasAttribute('appearance'),
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1726 workspaceFills: Math.abs(workspace.left) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1727 Math.abs(workspace.top) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1728 Math.abs(workspace.right - innerWidth) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1729 Math.abs(workspace.bottom - innerHeight) < 1,
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1730 };
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1731 });
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1732 assert.equal(mobile.aperturesTolerance, true, 'mobile apertures within tolerance at 360x640');
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1733 assert.equal(mobile.brandAligned, true, 'MrJuneJune aligns in the mobile top bar');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1734 assert.equal(mobile.brandVisible, true, 'MrJuneJune is visible on mobile');
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1735 assert.equal(
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1736 mobile.composerContentAligned,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1737 true,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1738 `composer content aligns inside frame aperture: ${JSON.stringify(mobile.composerGeometry)}`,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1739 );
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1740 assert.equal(mobile.composerFieldUsesSpace, true, 'composer field fills space beside send control');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1741 assert.equal(mobile.composerLabelHidden, true, 'Message label remains accessible but not visible');
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1742 assert.equal(mobile.composerVisible, true, 'composer visible');
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1743 assert.equal(mobile.dialogClosed, true, 'destination modal starts closed');
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1744 assert.equal(mobile.fillsViewport, true, 'shell fills viewport');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1745 assert.equal(mobile.fillsWidth, true, 'shell fills width');
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1746 assert.equal(mobile.hamburgerPresent, true, 'top-right menu trigger starts collapsed');
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1747 assert.equal(mobile.initialScroll, 0, 'no initial scroll');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1748 assert.equal(mobile.mobileArtIsCorrect, true, 'mobile background URL is background-frame-mobile.webp');
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1749 assert.equal(mobile.menuHidden, true, 'menu stays out of the two-aperture frame');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1750 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1751 mobile.menuInModal,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1752 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1753 `menu is hosted by the mobile modal: ${JSON.stringify(mobile)}`,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1754 );
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1755 assert.equal(mobile.noOverflow, true, 'no horizontal overflow at 360x640');
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1756 assert.equal(mobile.sendButtonCompact, true, 'mobile send control is a compact square icon button');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1757 assert.equal(mobile.telemetryHidden, true, 'mobile frame omits desktop telemetry');
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1758 assert.equal(
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1759 mobile.turnNavigationAligned,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1760 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1761 `turn navigation is centered and level: ${JSON.stringify(mobile.turnNavigationGeometry)}`,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1762 );
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1763 assert.equal(mobile.utilityHidden, true, 'destination view stays out of the frame');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1764 assert.equal(mobile.utilityInModal, true, 'destination view is hosted by the mobile modal');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1765 assert.equal(mobile.usesDesignSystemControls, true, 'composer uses styled Zenbu controls');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1766 assert.equal(mobile.workspaceFills, true, 'workspace fills full viewport');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1767 assert.equal(mobile.topLeftClear, true, 'hidden dialog triggers do not cover frame art');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1768
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1769 // The top-right trigger opens the modal menu.
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1770 await mobilePage.locator('[data-mobile-menu-toggle]').click();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1771 await mobilePage.locator('[data-mobile-destination-dialog]').waitFor({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1772 state: 'visible',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1773 });
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1774 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1775 await mobilePage.locator('[data-mobile-menu-toggle]')
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1776 .getAttribute('aria-expanded'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1777 'true',
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1778 'menu trigger reflects the open modal',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1779 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1780 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1781 await mobilePage.locator('mjj-jrpg-menu').isVisible(),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1782 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1783 'destination menu is visible inside the modal',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1784 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1785
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1786 // Every destination replaces the menu inside the same modal.
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1787 await mobilePage.locator('button[data-preview="conversations"]').click();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1788 await mobilePage.locator('mjj-conversation-archive').waitFor({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1789 state: 'visible',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1790 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1791 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1792 await mobilePage.locator('[data-mobile-destination-title]').textContent(),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1793 'Conversations',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1794 'conversation archive is a named modal destination',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1795 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1796 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1797 await mobilePage.locator('[data-mobile-destination-dialog]').isVisible(),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1798 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1799 'conversation archive remains in the modal',
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1800 );
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1801 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1802 await mobilePage.locator('.jrpg-mobile-destination-header').evaluate(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1803 header => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1804 const items = [...header.children].filter(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1805 item => getComputedStyle(item).display !== 'none',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1806 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1807 const centers = items.map(item => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1808 const rect = item.getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1809 return rect.top + rect.height / 2;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1810 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1811 return Math.max(...centers) - Math.min(...centers) < 2;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1812 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1813 ),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1814 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1815 'mobile modal header controls share one row',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1816 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1817
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1818 await mobilePage.locator('[data-mobile-destination-back]').click();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1819 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1820 await mobilePage.locator('mjj-jrpg-menu').isVisible(),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1821 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1822 'modal back action returns to destinations',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1823 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1824 await mobilePage.locator('button[data-preview="resume"]').click();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1825 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1826 await mobilePage.locator('[data-preview-content]').isVisible(),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1827 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1828 'resume view renders in the mobile modal',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1829 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1830 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1831 await mobilePage.locator('[data-mobile-destination-title]').textContent(),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1832 'Resume',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1833 'modal title follows the selected destination',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1834 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1835 await mobilePage.getByRole('button', {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1836 name: 'Close destination menu',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1837 }).click();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1838 await mobilePage.locator('[data-mobile-destination-dialog]').waitFor({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1839 state: 'hidden',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1840 });
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1841 assert.ok(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1842 await mobilePage.locator('[data-mobile-menu-toggle]').evaluate(el =>
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1843 el.tabIndex >= 0
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1844 ),
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1845 'mobile menu trigger remains keyboard accessible',
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1846 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1847 await mobileContext.close();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1848
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1849 // Test at 390x844
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1850 const mobile390Context = await browser.newContext({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1851 colorScheme: 'light',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1852 viewport: { width: 390, height: 844 },
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1853 });
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1854 const mobile390Page = await mobile390Context.newPage();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1855 await mobile390Page.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1856 const mobile390 = await mobile390Page.evaluate(() => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1857 const workspace = document.querySelector('.jrpg-workspace')
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1858 .getBoundingClientRect();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1859 const shell = document.querySelector('.jrpg-shell').getBoundingClientRect();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1860 const mobileArt = getComputedStyle(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1861 document.querySelector('.jrpg-workspace'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1862 ).backgroundImage;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1863 return {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1864 fillsViewport: shell.left === 0 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1865 shell.top === 0 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1866 Math.abs(shell.right - innerWidth) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1867 Math.abs(shell.bottom - innerHeight) < 1,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1868 mobileArtIsCorrect: mobileArt.includes('background-frame-mobile.webp'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1869 noOverflow: document.documentElement.scrollWidth <= innerWidth,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1870 workspaceFills: Math.abs(workspace.left) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1871 Math.abs(workspace.top) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1872 Math.abs(workspace.right - innerWidth) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1873 Math.abs(workspace.bottom - innerHeight) < 1,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1874 };
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1875 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1876 assert.equal(mobile390.fillsViewport, true, 'fills viewport at 390x844');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1877 assert.equal(mobile390.mobileArtIsCorrect, true, 'mobile art at 390x844');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1878 assert.equal(mobile390.noOverflow, true, 'no overflow at 390x844');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1879 assert.equal(mobile390.workspaceFills, true, 'workspace fills at 390x844');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1880 await mobile390Context.close();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1881
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1882 // Test at 320x568 (narrow)
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1883 const mobile320Context = await browser.newContext({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1884 colorScheme: 'light',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1885 viewport: { width: 320, height: 568 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1886 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1887 const mobile320Page = await mobile320Context.newPage();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1888 await mobile320Page.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1889 const mobile320 = await mobile320Page.evaluate(() => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1890 const workspace = document.querySelector('.jrpg-workspace')
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1891 .getBoundingClientRect();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1892 const shell = document.querySelector('.jrpg-shell').getBoundingClientRect();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1893 const composer = document.querySelector('mjj-composer')
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1894 .getBoundingClientRect();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1895 const menu = document.querySelector('mjj-jrpg-menu').getBoundingClientRect();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1896 const mobileArt = getComputedStyle(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1897 document.querySelector('.jrpg-workspace'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1898 ).backgroundImage;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1899 return {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1900 composerPresent: composer.width > 0 && composer.height > 0,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1901 fillsViewport: shell.left === 0 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1902 shell.top === 0 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1903 Math.abs(shell.right - innerWidth) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1904 Math.abs(shell.bottom - innerHeight) < 1,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1905 menuHidden: menu.width === 0 && menu.height === 0,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1906 mobileArtIsCorrect: mobileArt.includes('background-frame-mobile.webp'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1907 noOverflow: document.documentElement.scrollWidth <= innerWidth,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1908 workspaceFills: Math.abs(workspace.left) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1909 Math.abs(workspace.top) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1910 Math.abs(workspace.right - innerWidth) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1911 Math.abs(workspace.bottom - innerHeight) < 1,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1912 };
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1913 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1914 assert.equal(mobile320.composerPresent, true, 'composer present at 320x568');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1915 assert.equal(mobile320.fillsViewport, true, 'fills viewport at 320x568');
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1916 assert.equal(mobile320.menuHidden, true, 'menu remains modal-only at 320x568');
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1917 assert.equal(mobile320.mobileArtIsCorrect, true, 'mobile art at 320x568');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1918 assert.equal(mobile320.noOverflow, true, 'no overflow at 320x568');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1919 assert.equal(mobile320.workspaceFills, true, 'workspace fills at 320x568');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1920 await mobile320Context.close();
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1921
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1922 const shortContext = await browser.newContext({
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1923 colorScheme: 'dark',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1924 viewport: { width: 900, height: 500 },
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1925 });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1926 const shortPage = await shortContext.newPage();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1927 await shortPage.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1928 const shortLayout = await shortPage.evaluate(() => {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1929 const scene = document.querySelector('.jrpg-scene').getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1930 const character = document.querySelector('mjj-jrpg-character')
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1931 .getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1932 const chat = document.querySelector('mjj-jrpg-chat')
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1933 .getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1934 return {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1935 characterInside: character.left >= scene.left &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1936 character.right <= scene.right,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1937 chatInside: chat.left >= scene.left && chat.right <= scene.right,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1938 noSceneOverflow: document.querySelector('.jrpg-scene').scrollWidth <=
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1939 document.querySelector('.jrpg-scene').clientWidth,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1940 };
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1941 });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1942 assert.deepEqual(shortLayout, {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1943 characterInside: true,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1944 chatInside: true,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1945 noSceneOverflow: true,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1946 });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1947 await shortContext.close();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1948
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1949 const forcedColorsContext = await browser.newContext({
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1950 forcedColors: 'active',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1951 viewport: { width: 1280, height: 900 },
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1952 });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1953 const forcedColorsPage = await forcedColorsContext.newPage();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1954 await forcedColorsPage.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1955 assert.deepEqual(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1956 await forcedColorsPage.evaluate(() => ({
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1957 sceneBar: getComputedStyle(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1958 document.querySelector('.jrpg-scene'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1959 '::before',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1960 ).backgroundImage,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1961 workspace: getComputedStyle(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1962 document.querySelector('.jrpg-workspace'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1963 ).backgroundImage,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1964 })),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1965 {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1966 sceneBar: 'none',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1967 workspace: 'none',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1968 },
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1969 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1970 await forcedColorsContext.close();
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1971 }
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1972
242
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1973 async function testHlsPlayer(browser, siteRoot) {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1974 const page = await browser.newPage();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1975 const errors = [];
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1976 const mediaRequests = [];
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1977 let testingExpectedFailure = false;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1978 let testingExpectedReload = false;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1979 page.on('pageerror', error => errors.push(`pageerror: ${error.message}`));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1980 page.on('console', message => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1981 if (message.type() !== 'error') return;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1982 if (testingExpectedFailure &&
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1983 message.text().startsWith('Failed to load resource:')) return;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1984 errors.push(`console: ${message.text()}`);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1985 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1986 page.on('requestfailed', request => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1987 if (testingExpectedReload &&
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1988 request.failure()?.errorText === 'net::ERR_ABORTED') return;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1989 errors.push(`requestfailed: ${request.url()} ${request.failure()?.errorText || ''}`);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1990 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1991 page.on('request', request => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1992 if (/\.(?:m3u8|m4s|mp4)(?:\?|$)/.test(request.url())) {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1993 mediaRequests.push(request.url());
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1994 }
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1995 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1996
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1997 const playlistResponse = await fetch(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1998 `${baseUrl}/public/hls-sample/master.m3u8`,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
1999 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2000 assert.equal(playlistResponse.status, 200);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2001 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2002 playlistResponse.headers.get('content-type') || '',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2003 /^application\/vnd\.apple\.mpegurl/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2004 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2005 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2006 await playlistResponse.text(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2007 /#EXT-X-STREAM-INF:.*CODECS="vp09\.00\.10\.08,opus"/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2008 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2009
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2010 const variantResponse = await fetch(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2011 `${baseUrl}/public/hls-sample/vp9-stream.m3u8`,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2012 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2013 assert.equal(variantResponse.status, 200);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2014 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2015 await variantResponse.text(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2016 /#EXT-X-MAP:URI="vp9-init\.mp4"/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2017 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2018
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2019 const segmentResponse = await fetch(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2020 `${baseUrl}/public/hls-sample/vp9-segment000.m4s`,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2021 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2022 assert.equal(segmentResponse.status, 200);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2023 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2024 segmentResponse.headers.get('content-type') || '',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2025 /^video\/iso\.segment/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2026 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2027 const transportStreamResponse = await fetch(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2028 `${baseUrl}/public/hls-sample/h264-ts-segment000.ts`,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2029 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2030 assert.equal(transportStreamResponse.status, 200);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2031 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2032 transportStreamResponse.headers.get('content-type') || '',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2033 /^video\/mp2t/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2034 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2035 assert.ok((await transportStreamResponse.arrayBuffer()).byteLength > 0);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2036
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2037 await page.goto(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2038 `${baseUrl}/tools/hls_player?url=${encodeURIComponent('/public/hls-sample/master.m3u8')}`,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2039 {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2040 waitUntil: 'networkidle',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2041 },
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2042 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2043 await page.getByRole('button', { name: 'Sample', exact: true }).waitFor();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2044 assert.equal(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2045 await page.locator('#hlsUrl').evaluate(input => input.defaultValue),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2046 '/public/hls-sample/h264-ts-stream.m3u8',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2047 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2048 await page.waitForFunction(() => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2049 const status = document.querySelector('#hlsStatus');
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2050 return status?.dataset.state === 'ready' ||
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2051 status?.dataset.state === 'error';
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2052 }, null, { timeout: 15000 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2053 const terminalState = await page.locator('#hlsStatus').getAttribute('data-state');
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2054 if (terminalState !== 'ready') {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2055 throw new Error(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2056 `HLS player failed: ${await page.locator('#hlsStatus').textContent()}\n${errors.join('\n')}`,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2057 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2058 }
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2059 assert.match(await page.locator('#hlsStatus').textContent(), /Stream ready/);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2060 assert.equal(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2061 await page.locator('[data-detail="mode"]').textContent(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2062 'hls.js',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2063 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2064 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2065 await page.locator('[data-detail="segments"]').textContent(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2066 /Managed by hls\.js|adaptive levels/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2067 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2068 await page.waitForFunction(() => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2069 const video = document.querySelector('#hlsVideo');
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2070 return video.readyState >= HTMLMediaElement.HAVE_METADATA &&
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2071 Number.isFinite(video.duration) &&
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2072 video.duration >= 14;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2073 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2074 const firstFrame = await page.locator('#hlsVideo').evaluate(video => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2075 const canvas = document.createElement('canvas');
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2076 canvas.width = video.videoWidth;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2077 canvas.height = video.videoHeight;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2078 const context = canvas.getContext('2d');
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2079 context.drawImage(video, 0, 0);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2080 const pixels = context.getImageData(0, 0, canvas.width, canvas.height).data;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2081 let total = 0;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2082 for (let index = 0; index < pixels.length; index += 4) {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2083 total += pixels[index] + pixels[index + 1] + pixels[index + 2];
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2084 }
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2085 return total / (canvas.width * canvas.height * 3);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2086 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2087 assert.ok(firstFrame > 10, `Initial HLS frame is black: ${firstFrame}`);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2088 await page.locator('#hlsVideo').evaluate(video => video.play());
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2089 await page.waitForFunction(() => document.querySelector('#hlsVideo').currentTime > 0.2);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2090 await page.locator('#hlsVideo').evaluate(video => video.pause());
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2091 assert.ok(mediaRequests.some(url => url.endsWith('/hls-sample/master.m3u8')));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2092 assert.ok(mediaRequests.some(url => url.endsWith('-stream.m3u8')));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2093 assert.ok(mediaRequests.some(url => url.endsWith('-init.mp4')));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2094 assert.ok(mediaRequests.some(url => /-segment\d+\.m4s$/.test(url)));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2095
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2096 await page.evaluate(() => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2097 window.hlsPlayer.hls.trigger(window.Hls.Events.ERROR, {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2098 fatal: true,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2099 type: window.Hls.ErrorTypes.MEDIA_ERROR,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2100 details: 'testRuntimeFailure',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2101 error: new Error('runtime segment failed'),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2102 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2103 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2104 await page.locator('#hlsStatus[data-state="error"]').waitFor();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2105 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2106 await page.locator('#hlsStatus').textContent(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2107 /runtime segment failed/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2108 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2109 await page.locator('#hlsUrl').fill('/public/hls-sample/master.m3u8');
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2110 await page.getByRole('button', { name: 'Load', exact: true }).click();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2111 await page.locator('#hlsStatus[data-state="ready"]').waitFor();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2112
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2113 let delayedSegment = true;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2114 await page.route('**/hls-sample/vp9-segment000.m4s', async route => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2115 if (delayedSegment) {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2116 delayedSegment = false;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2117 await new Promise(resolve => setTimeout(resolve, 250));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2118 }
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2119 await route.continue();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2120 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2121 testingExpectedReload = true;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2122 await page.locator('#hlsUrl').fill('/public/hls-sample/master.m3u8');
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2123 await page.getByRole('button', { name: 'Load', exact: true }).click();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2124 await page.waitForTimeout(25);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2125 await page.getByRole('button', { name: 'Load', exact: true }).click();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2126 await page.locator('#hlsStatus[data-state="ready"]').waitFor();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2127 testingExpectedReload = false;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2128 assert.match(await page.locator('#hlsStatus').textContent(), /Stream ready/);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2129
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2130 await page.evaluate(() => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2131 window.__hlsObjectUrls = { created: [], revoked: [] };
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2132 const createObjectURL = URL.createObjectURL.bind(URL);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2133 const revokeObjectURL = URL.revokeObjectURL.bind(URL);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2134 URL.createObjectURL = value => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2135 const url = createObjectURL(value);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2136 window.__hlsObjectUrls.created.push(url);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2137 return url;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2138 };
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2139 URL.revokeObjectURL = url => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2140 window.__hlsObjectUrls.revoked.push(url);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2141 revokeObjectURL(url);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2142 };
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2143 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2144 const localFiles = listFiles(path.join(siteRoot, 'public/hls-sample'));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2145 await page.locator('#hlsFiles').setInputFiles(localFiles);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2146 await page.waitForFunction(() =>
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2147 document.querySelector('#hlsUrl')?.value.startsWith('Local: ')
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2148 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2149 await page.locator('#hlsStatus[data-state="ready"]').waitFor();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2150 assert.match(await page.locator('#hlsUrl').inputValue(), /^Local: /);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2151 assert.equal(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2152 await page.locator('[data-detail="mode"]').textContent(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2153 'hls.js',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2154 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2155 await page.locator('#hlsVideo').evaluate(video => video.play());
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2156 await page.waitForFunction(() => document.querySelector('#hlsVideo').currentTime > 0.3);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2157 await page.locator('#hlsVideo').evaluate(video => video.pause());
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2158 const incompleteLocalFiles = localFiles.filter(file =>
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2159 file.endsWith('master.m3u8') ||
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2160 file.endsWith('vp9-stream.m3u8')
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2161 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2162 await page.locator('#hlsFiles').setInputFiles(incompleteLocalFiles);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2163 await page.locator('#hlsStatus[data-state="error"]').waitFor();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2164 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2165 await page.locator('#hlsStatus').textContent(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2166 /Local HLS file is missing/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2167 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2168 const objectUrlCounts = await page.evaluate(() => ({
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2169 created: window.__hlsObjectUrls.created.length,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2170 revoked: window.__hlsObjectUrls.revoked.length,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2171 }));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2172 assert.ok(objectUrlCounts.created > 10, JSON.stringify(objectUrlCounts));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2173 assert.ok(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2174 objectUrlCounts.revoked >= objectUrlCounts.created,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2175 JSON.stringify(objectUrlCounts),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2176 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2177
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2178 await page.route('**/invalid.m3u8', route => route.fulfill({
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2179 status: 404,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2180 body: 'not found',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2181 }));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2182 testingExpectedFailure = true;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2183 await page.locator('#hlsUrl').fill(`${baseUrl}/invalid.m3u8`);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2184 await page.getByRole('button', { name: 'Load', exact: true }).click();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2185 await page.locator('#hlsStatus[data-state="error"]').waitFor();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2186 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2187 await page.locator('#hlsStatus').textContent(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2188 /404|manifestLoadError|Playlist request failed/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2189 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2190
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2191 if (errors.length) throw new Error(errors.join('\n'));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2192 await page.close();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2193 }
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2194
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2195 function findFreePort() {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2196 return new Promise((resolve, reject) => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2197 const socket = net.createServer();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2198 socket.once('error', reject);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2199 socket.listen(0, '127.0.0.1', () => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2200 const address = socket.address();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2201 socket.close(error => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2202 if (error) reject(error);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2203 else resolve(String(address.port));
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2204 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2205 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2206 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2207 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2208
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2209 /* ------------------------------------------------------------------ */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2210 /* Conversation URL routing regression tests (Fixes 1–4) */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2211 /* ------------------------------------------------------------------ */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2212
265
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2213 async function testRoleGreetings(browser) {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2214 const cases = [
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2215 {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2216 name: 'guest',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2217 session: {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2218 kind: 'guest',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2219 csrfToken: 'guest-greeting-csrf',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2220 quota: null,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2221 },
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2222 expected: 'Hi, my name is Epi. June usually calls me Epi-chan.',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2223 },
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2224 {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2225 name: 'invited',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2226 session: {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2227 kind: 'user',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2228 username: 'friend',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2229 role: 'member',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2230 mustChangePassword: false,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2231 csrfToken: 'friend-greeting-csrf',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2232 quota: null,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2233 },
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2234 expected: 'Since June invited you, I can be a little more casual.',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2235 },
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2236 {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2237 name: 'admin',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2238 session: {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2239 kind: 'user',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2240 username: 'june',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2241 role: 'admin',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2242 mustChangePassword: false,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2243 csrfToken: 'admin-greeting-csrf',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2244 quota: null,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2245 },
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2246 expected: 'Hi June! I’m Epi-chan.',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2247 },
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2248 ];
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2249
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2250 for (const testCase of cases) {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2251 const context = await browser.newContext({ serviceWorkers: 'block' });
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2252 const page = await context.newPage();
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2253 await page.route('**/api/auth/session', route => route.fulfill({
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2254 status: 200,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2255 contentType: 'application/json',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2256 body: JSON.stringify(testCase.session),
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2257 }));
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2258 await page.route('**/api/conversations**', route => route.fulfill({
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2259 status: 200,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2260 contentType: 'application/json',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2261 body: JSON.stringify({ conversations: [], cursor: null }),
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2262 }));
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2263 await page.goto(`${baseUrl}/jrpg`, { waitUntil: 'domcontentloaded' });
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2264 const greeting = page.locator('[data-greeting]');
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2265 await greeting.waitFor({ state: 'visible' });
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2266 if (testCase.name === 'guest') {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2267 await page.locator('[data-greeting][data-streaming="true"]').waitFor({
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2268 state: 'visible',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2269 });
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2270 }
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2271 await page.waitForFunction(() => {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2272 const item = document.querySelector('[data-greeting]');
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2273 return item && !item.hasAttribute('data-streaming');
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2274 });
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2275 assert.match(
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2276 await greeting.locator('p').textContent(),
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2277 new RegExp(testCase.expected.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')),
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2278 `${testCase.name} receives its role-specific Epi greeting`,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2279 );
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2280 await context.close();
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2281 }
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2282 }
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2283
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2284 async function testConversationRouting(browser) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2285 const CONV_A = 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa';
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2286 const CONV_B = 'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb';
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2287 const GUEST_SESSION = {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2288 kind: 'guest', csrfToken: 'test-csrf',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2289 quota: {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2290 turnsLimit: 10, turnsUsed: 0, turnsRemaining: 10,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2291 outputTokensLimit: 10000, outputTokensUsed: 0,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2292 outputTokensReserved: 0, outputTokensRemaining: 10000,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2293 resetsAt: Math.floor(Date.now() / 1000) + 86400,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2294 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2295 };
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2296
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2297 /* Returning without a conversation URL stays fresh until the user chooses one. */
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2298 {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2299 const context = await browser.newContext({ serviceWorkers: 'block' });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2300 await context.addInitScript(id => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2301 sessionStorage.setItem('mjj-jrpg-conversation-id', id);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2302 }, CONV_A);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2303 const page = await context.newPage();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2304 let detailRequestCount = 0;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2305 await page.route('**/api/auth/session', route => route.fulfill({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2306 status: 200, contentType: 'application/json',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2307 body: JSON.stringify(GUEST_SESSION),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2308 }));
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2309 await page.route('**/api/conversations**', route => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2310 const url = new URL(route.request().url());
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2311 if (url.pathname === '/api/conversations') {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2312 return route.fulfill({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2313 status: 200, contentType: 'application/json',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2314 body: JSON.stringify({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2315 conversations: [{
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2316 id: CONV_A,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2317 title: 'Earlier quest',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2318 turn_count: 2,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2319 }],
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2320 cursor: null,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2321 }),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2322 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2323 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2324 return route.fulfill({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2325 status: 404, contentType: 'application/json',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2326 body: JSON.stringify({ error: { message: 'Not found' } }),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2327 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2328 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2329 await page.route(`**/api/conversations/${CONV_A}`, route => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2330 detailRequestCount += 1;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2331 return route.fulfill({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2332 status: 200, contentType: 'application/json',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2333 body: JSON.stringify({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2334 id: CONV_A,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2335 title: 'Earlier quest',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2336 turns: [{ role: 'assistant', content: 'Welcome back.' }],
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2337 }),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2338 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2339 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2340
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2341 await page.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2342 assert.equal(detailRequestCount, 0, 'latest conversation is not opened automatically');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2343 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2344 new URL(page.url()).searchParams.has('conversation'),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2345 false,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2346 'returning visit remains a fresh conversation URL',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2347 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2348 await page.waitForFunction(() => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2349 const greeting = document.querySelector('[data-greeting] p');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2350 return greeting?.textContent.includes('Open Conversations');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2351 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2352 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2353 await page.evaluate(() =>
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2354 sessionStorage.getItem('mjj-jrpg-conversation-id')),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2355 null,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2356 'stale active conversation state is cleared',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2357 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2358
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2359 await page.locator('button[data-preview="conversations"]').click();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2360 const selectedConversation = page.waitForResponse(response =>
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2361 new URL(response.url()).pathname === `/api/conversations/${CONV_A}`);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2362 await page.locator('[data-conv-open]').click();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2363 assert.equal((await selectedConversation).status(), 200);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2364 assert.ok(detailRequestCount >= 1, 'conversation opens after explicit selection');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2365 await page.waitForFunction(id =>
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2366 new URL(window.location.href).searchParams.get('conversation') === id,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2367 CONV_A);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2368 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2369 new URL(page.url()).searchParams.get('conversation'),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2370 CONV_A,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2371 'explicit selection writes the conversation URL',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2372 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2373 await context.close();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2374 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2375
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2376 /* ---- Fix 3: malformed ?conversation param must not fall back to sessionStorage ---- */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2377 {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2378 const storedId = 'cccccccc-cccc-4ccc-8ccc-cccccccccccc';
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2379 const context = await browser.newContext({ serviceWorkers: 'block' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2380 await context.addInitScript(id => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2381 sessionStorage.setItem('mjj-jrpg-conversation-id', id);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2382 }, storedId);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2383 const page = await context.newPage();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2384 const storedIdFetched = [];
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2385 await page.route('**/api/auth/session', route => route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2386 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2387 body: JSON.stringify(GUEST_SESSION),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2388 }));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2389 await page.route('**/api/conversations**', route => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2390 const url = new URL(route.request().url());
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2391 if (url.pathname.endsWith(`/${storedId}`)) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2392 storedIdFetched.push(route.request().url());
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2393 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2394 if (url.pathname === '/api/conversations') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2395 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2396 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2397 body: JSON.stringify({ conversations: [], cursor: null }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2398 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2399 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2400 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2401 status: 404, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2402 body: JSON.stringify({ error: { message: 'Not found' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2403 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2404 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2405 await page.route('**/api/conversations/claim', route => route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2406 status: 503,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2407 contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2408 body: JSON.stringify({ error: { message: 'Service unavailable' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2409 }));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2410 await page.goto(`${baseUrl}/jrpg?conversation=not-a-valid-uuid`, {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2411 waitUntil: 'networkidle',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2412 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2413 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2414 storedIdFetched.length, 0,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2415 'Fix 3: malformed ?conversation param must not trigger sessionStorage fallback',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2416 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2417 await context.close();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2418 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2419
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2420 /* ---- Fix 4: legacy claim: key retained on 5xx, button re-renders and re-fires ---- */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2421 {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2422 const legacyStoredId = 'dddddddd-dddd-4ddd-8ddd-dddddddddddd';
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2423 const context = await browser.newContext({ serviceWorkers: 'block' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2424 /* Seed CONVERSATION_STORAGE_KEY so init migrates it to CONVERSATION_LEGACY_KEY */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2425 await context.addInitScript(id => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2426 sessionStorage.setItem('mjj-jrpg-conversation-id', id);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2427 }, legacyStoredId);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2428 const page = await context.newPage();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2429 const pageErrors = [];
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2430 page.on('pageerror', e => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2431 if (!e.message.startsWith('Failed to load resource:')) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2432 pageErrors.push(`pageerror: ${e.message}`);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2433 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2434 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2435 await page.route('**/api/auth/session', route => route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2436 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2437 body: JSON.stringify({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2438 kind: 'user', username: 'tester', role: 'member',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2439 csrfToken: 'test-csrf', quota: null,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2440 }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2441 }));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2442 await page.route('**/api/conversations**', route => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2443 const url = new URL(route.request().url());
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2444 const req = route.request();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2445 if (url.pathname === '/api/conversations' && req.method() === 'GET') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2446 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2447 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2448 body: JSON.stringify({ conversations: [], cursor: null }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2449 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2450 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2451 if (url.pathname === `/api/conversations/${legacyStoredId}` && req.method() === 'GET') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2452 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2453 status: 404, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2454 body: JSON.stringify({ error: { message: 'Not found' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2455 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2456 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2457 if (url.pathname === '/api/conversations/claim' && req.method() === 'POST') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2458 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2459 status: 503, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2460 body: JSON.stringify({ error: { message: 'Service unavailable' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2461 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2462 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2463 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2464 status: 404, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2465 body: JSON.stringify({ error: { message: 'Not found' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2466 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2467 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2468 await page.route('**/api/conversations/claim', route => route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2469 status: 503,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2470 contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2471 body: JSON.stringify({ error: { message: 'Service unavailable' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2472 }));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2473 await page.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2474
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2475 /* Open archive panel so the legacy claim status is visible */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2476 await page.locator('button[data-preview="conversations"]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2477 await page.locator('mjj-conversation-archive').waitFor({ state: 'visible' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2478
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2479 /* Init should have called showLegacyClaim() — wait for the button */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2480 await page.waitForFunction(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2481 () => document.querySelector('[data-archive-claim]') !== null,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2482 null, { timeout: 5000 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2483 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2484
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2485 /* First claim attempt — returns 503 */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2486 const firstClaimResponse = page.waitForResponse(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2487 response => response.url().includes('/api/conversations/claim'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2488 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2489 await page.locator('[data-archive-claim]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2490 const firstClaimStatus = (await firstClaimResponse).status();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2491 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2492 firstClaimStatus,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2493 503,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2494 `claim fixture returns the mocked service failure, got ${firstClaimStatus}`,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2495 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2496
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2497 /* Wait for the retry state to appear: showLegacyClaim re-rendered with error msg */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2498 await page.waitForFunction(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2499 () => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2500 const status = document.querySelector('[data-archive-status]');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2501 return status && !status.hidden && status.textContent.includes('Claim failed');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2502 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2503 null, { timeout: 5000 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2504 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2505
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2506 /* Key must be retained in sessionStorage on 5xx */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2507 const keyAfterFail = await page.evaluate(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2508 () => sessionStorage.getItem('mjj-jrpg-legacy-claim'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2509 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2510 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2511 keyAfterFail, legacyStoredId,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2512 'Fix 4: CONVERSATION_LEGACY_KEY must be retained after 5xx failure',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2513 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2514
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2515 /* Button must be present and enabled for retry */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2516 await page.locator('[data-archive-claim]').waitFor({ state: 'visible' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2517
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2518 /* Tag the current button so we can detect when it's replaced by a second re-render */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2519 await page.locator('[data-archive-claim]').evaluate(btn => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2520 btn.dataset.claimGen = '1';
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2521 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2522
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2523 /* Second click: must dispatch event again — proves no {once:true} on button */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2524 await page.locator('[data-archive-claim]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2525
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2526 /* Wait for the button to be replaced (showLegacyClaim called again = handler ran) */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2527 await page.waitForFunction(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2528 () => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2529 const btn = document.querySelector('[data-archive-claim]');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2530 return btn !== null && btn.dataset.claimGen !== '1';
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2531 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2532 null, { timeout: 5000 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2533 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2534
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2535 assert.deepEqual(pageErrors, [], 'no page errors in legacy claim test');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2536 await context.close();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2537 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2538
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2539 /* ---- Fix 1: popstate during active stream converges URL and UI ---- */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2540 {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2541 let releaseStream = () => {};
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2542 const streamGate = new Promise(resolve => { releaseStream = resolve; });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2543
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2544 const context = await browser.newContext();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2545 const page = await context.newPage();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2546 const pageErrors = [];
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2547 page.on('pageerror', e => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2548 if (!e.message.startsWith('Failed to load resource:')) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2549 pageErrors.push(`pageerror: ${e.message}`);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2550 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2551 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2552 /* Suppress expected abort-network errors from the held-then-aborted stream */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2553 page.on('requestfailed', request => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2554 if (request.failure()?.errorText === 'net::ERR_ABORTED') return;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2555 pageErrors.push(`requestfailed: ${request.url()} ${request.failure()?.errorText || ''}`);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2556 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2557
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2558 await page.route('**/api/auth/session', route => route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2559 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2560 body: JSON.stringify(GUEST_SESSION),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2561 }));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2562 await page.route('**/api/conversations**', async route => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2563 const url = new URL(route.request().url());
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2564 const req = route.request();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2565 if (url.pathname === '/api/conversations' && req.method() === 'GET') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2566 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2567 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2568 body: JSON.stringify({ conversations: [], cursor: null }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2569 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2570 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2571 if (url.pathname === '/api/conversations' && req.method() === 'POST') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2572 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2573 status: 201, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2574 body: JSON.stringify({ id: CONV_A }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2575 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2576 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2577 if (url.pathname.endsWith('/turns') && req.method() === 'POST') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2578 /* Hold the SSE stream until the test releases it */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2579 await streamGate;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2580 try { await route.abort(); } catch { /* request may already be aborted */ }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2581 return;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2582 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2583 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2584 status: 404, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2585 body: JSON.stringify({ error: { message: 'Not found' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2586 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2587 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2588
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2589 await page.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2590 await page.waitForFunction(
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2591 () => !document.querySelector('mjj-composer textarea')?.disabled,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2592 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2593
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2594 /* Submit — creates conversation via pushState and starts stream */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2595 await page.locator('#jrpg-message').fill('routing race test');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2596 await page.locator('#jrpg-message').press('Enter');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2597
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2598 /* Stream is now active */
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2599 await page.locator('[data-composer-cancel-owner]').waitFor({ state: 'visible' });
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2600
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2601 const urlDuringStream = page.url();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2602 assert.ok(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2603 urlDuringStream.includes('conversation='),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2604 `Fix 1: URL must have ?conversation during stream: ${urlDuringStream}`,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2605 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2606
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2607 /* Navigate back while stream is active — URL already changes here */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2608 await page.goBack();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2609
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2610 /* Stream abort + pending-popstate application: cancel control disappears */
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2611 await page.locator('[data-composer-cancel-owner]').waitFor({ state: 'hidden' });
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2612
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2613 /* URL and UI must converge to the pre-stream state */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2614 const finalUrl = page.url();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2615 assert.ok(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2616 !finalUrl.includes('conversation='),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2617 `Fix 1: URL must not have ?conversation after popstate back: ${finalUrl}`,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2618 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2619 assert.equal(
265
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2620 await page.locator(
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2621 '.jrpg-message[data-streaming="true"]:not([data-greeting])',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2622 ).count(),
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2623 0,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2624 'Fix 1: no streaming message must remain after popstate back',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2625 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2626
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2627 releaseStream(); /* clean up the held route */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2628 assert.deepEqual(pageErrors, [], 'no page errors in popstate-during-stream test');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2629 await context.close();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2630 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2631
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2632 /* ---- Fix 2: openSeq incremented on no-conv popstate, invalidates pending open ---- */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2633 {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2634 let resolveConvBFetch = () => {};
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2635 const convBFetchGate = new Promise(resolve => { resolveConvBFetch = resolve; });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2636
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2637 const context = await browser.newContext();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2638 const page = await context.newPage();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2639 const pageErrors = [];
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2640 page.on('pageerror', e => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2641 if (!e.message.startsWith('Failed to load resource:')) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2642 pageErrors.push(`pageerror: ${e.message}`);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2643 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2644 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2645
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2646 await page.route('**/api/auth/session', route => route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2647 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2648 body: JSON.stringify(GUEST_SESSION),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2649 }));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2650 await page.route('**/api/conversations**', async route => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2651 const url = new URL(route.request().url());
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2652 const req = route.request();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2653 /* Empty archive: no auto-open, no gate deadlock */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2654 if (url.pathname === '/api/conversations' && req.method() === 'GET') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2655 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2656 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2657 body: JSON.stringify({ conversations: [], cursor: null }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2658 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2659 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2660 /* The archive-open click will trigger this; hold it with the gate */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2661 if (url.pathname === `/api/conversations/${CONV_B}` && req.method() === 'GET') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2662 await convBFetchGate;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2663 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2664 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2665 body: JSON.stringify({ id: CONV_B, title: 'Conv B', turns: [] }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2666 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2667 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2668 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2669 status: 404, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2670 body: JSON.stringify({ error: { message: 'Not found' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2671 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2672 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2673
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2674 /* Empty archive so init completes without auto-opening any conversation */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2675 await page.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2676
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2677 /* Open archive panel — this pushes a history entry (conversations panel) */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2678 await page.locator('button[data-preview="conversations"]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2679 await page.locator('mjj-conversation-archive').waitFor({ state: 'visible' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2680
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2681 /* Inject Conv B into the archive list without triggering an API fetch */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2682 await page.evaluate(id => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2683 document.querySelector('mjj-conversation-archive')
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2684 ?.addConversation({ id, title: 'Conv B', turn_count: 0 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2685 }, CONV_B);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2686
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2687 await page.waitForFunction(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2688 id => [...document.querySelectorAll('[data-conv-item]')]
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2689 .some(item => item._convId === id),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2690 CONV_B,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2691 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2692
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2693 /* Click Conv B — archive-open fires, fetch held by convBFetchGate */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2694 await page.evaluate(id => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2695 for (const item of document.querySelectorAll('[data-conv-item]')) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2696 if (item._convId === id) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2697 item.querySelector('[data-conv-open]')?.click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2698 break;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2699 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2700 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2701 }, CONV_B);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2702
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2703 /* Brief pause so archive-open can increment openSeq and start the fetch */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2704 await page.waitForTimeout(80);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2705
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2706 /* Navigate back — popstate fires with no-conv state, openSeq is incremented */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2707 await page.goBack();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2708 await page.waitForTimeout(80);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2709
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2710 /* Release the held fetch — the archive-open handler should ignore it */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2711 resolveConvBFetch();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2712 await page.waitForTimeout(300);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2713
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2714 /* currentConversationId must remain null (no aria-current item) */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2715 const currentAriaItem = await page.evaluate(() => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2716 const btn = document.querySelector('[data-conv-open][aria-current="true"]');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2717 return btn ? (btn.closest('[data-conv-item]')?._convId ?? null) : null;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2718 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2719 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2720 currentAriaItem, null,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2721 'Fix 2: pending archive-open must not overwrite no-conv popstate',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2722 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2723
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2724 assert.deepEqual(pageErrors, [], 'no page errors in openSeq test');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2725 await context.close();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2726 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2727 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2728
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2729 (async () => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2730 assert.ok(RUNFILES);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2731 assert.ok(WORKSPACE);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2732 const runfilesWorkspace = path.join(RUNFILES, WORKSPACE);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2733 const serverBinary = path.join(
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2734 runfilesWorkspace,
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
2735 'mrjunejune/mrjunejune_server_debug',
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2736 );
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2737 const siteRoot = path.join(runfilesWorkspace, 'mrjunejune/src');
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2738 const fakeSidecar = path.join(
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2739 runfilesWorkspace,
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2740 'mrjunejune/test/inference_bridge_fake_sidecar',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2741 );
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2742 const tempDirectory = fs.mkdtempSync(
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2743 path.join(os.tmpdir(), 'mrjunejune-theme-test-'),
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2744 );
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2745 const chromiumPath = path.resolve(process.env.CHROMIUM_PATH);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2746 const serverLogs = [];
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2747 let server;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2748 let browser;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2749
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2750 try {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2751 port = await findFreePort();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2752 baseUrl = `http://127.0.0.1:${port}`;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2753 const pngFiles = listFiles(siteRoot).filter(file => file.endsWith('.png'));
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2754 assert.deepEqual(pngFiles, [], `PNG files leaked into runfiles: ${pngFiles}`);
258
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2755 for (const file of listFiles(siteRoot).filter(file =>
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2756 file.endsWith('.html')
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2757 )) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2758 const source = fs.readFileSync(file, 'utf8');
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2759 for (const primitive of source.matchAll(/<zen-button\b([^>]*)>/g)) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2760 assert.match(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2761 primitive[1],
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2762 /\bsize=["'](?:xs|sm|md|lg|xl)["']/,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2763 `${path.relative(siteRoot, file)} has an unsized zen-button`,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2764 );
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2765 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2766 assert.deepEqual(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2767 primitiveOwnershipViolations(source),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2768 [],
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2769 `${path.relative(siteRoot, file)} violates primitive ownership`,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2770 );
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2771 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2772 for (const file of listFiles(siteRoot).filter(file =>
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2773 /\.(?:css|html|js)$/.test(file) &&
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2774 !file.includes(`${path.sep}public${path.sep}design-system${path.sep}`)
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2775 )) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2776 const source = fs.readFileSync(file, 'utf8');
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2777 assert.doesNotMatch(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2778 source,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2779 /var\(\s*--zen-/,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2780 `${path.relative(siteRoot, file)} consumes a deprecated token`,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2781 );
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
2782 }
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2783
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2784 server = spawn(serverBinary, [], {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2785 cwd: runfilesWorkspace,
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2786 env: {
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2787 ...process.env,
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2788 MRJUNEJUNE_PORT: port,
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2789 MRJUNEJUNE_DB_PATH: path.join(tempDirectory, 'site.db'),
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2790 MRJUNEJUNE_INFERENCE_SIDECAR_PATH: fakeSidecar,
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2791 MRJUNEJUNE_COPILOT_CLI_PATH: fakeSidecar,
265
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2792 MRJUNEJUNE_ALLOW_GUEST_INFERENCE: '1',
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2793 },
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2794 stdio: ['ignore', 'pipe', 'pipe'],
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2795 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2796 server.stdout.on('data', chunk => serverLogs.push(chunk.toString()));
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2797 server.stderr.on('data', chunk => serverLogs.push(chunk.toString()));
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2798 await waitForServer(server, serverLogs);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2799
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2800 const home = await (await fetch(baseUrl)).text();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2801 const dogGame = await (
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2802 await fetch(`${baseUrl}/public/dog-game.js`)
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2803 ).text();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2804 const manifest = await (
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2805 await fetch(`${baseUrl}/public/manifest.json`)
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2806 ).text();
242
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2807 const serviceWorker = await (
256
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
2808 await fetch(`${baseUrl}/sw.js`)
242
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2809 ).text();
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2810 for (const source of [home, dogGame, manifest]) {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2811 assert.doesNotMatch(source, /\.png(?:["')]|$)/i);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2812 }
265
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2813 assert.match(serviceWorker, /v35-role-greeting/);
256
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
2814 assert.match(
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
2815 await (
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
2816 await fetch(`${baseUrl}/public/pwa-register.js`)
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
2817 ).text(),
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
2818 /register\('\/sw\.js', \{ scope: '\/' \}\)/,
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
2819 );
242
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2820 assert.ok(serviceWorker.includes("startsWith('/tools/hls_player')"));
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
2821 assert.ok(serviceWorker.includes("url.hostname === 'localhost'"));
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
2822 assert.ok(serviceWorker.includes("url.hostname === '127.0.0.1'"));
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
2823 assert.ok(!serviceWorker.includes("startsWith('/jrpg')"));
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2824
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2825 for (const asset of [
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2826 'sprite_shiba0.webp',
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2827 'dog-treat.webp',
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2828 'start-large.webp',
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2829 'icon-192.webp',
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2830 'vscode.webp',
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2831 ]) {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2832 const response = await fetch(`${baseUrl}/public/${asset}`);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2833 assert.equal(response.status, 200, asset);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2834 assert.ok((await response.arrayBuffer()).byteLength > 0, asset);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2835 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2836
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2837 browser = await chromium.launch({
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2838 executablePath: chromiumPath,
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2839 headless: true,
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2840 args: ['--no-sandbox'],
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2841 });
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2842 if (runsSuite('core')) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2843 const paper = await sampleTheme(browser, 'paper');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2844 const ink = await sampleTheme(browser, 'ink');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2845 const playful = await sampleTheme(browser, 'playful');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2846 const automatic = await sampleTheme(browser, 'auto');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2847 assert.equal(paper.rootTheme, 'paper');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2848 assert.equal(ink.rootTheme, 'ink');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2849 assert.equal(playful.rootTheme, 'playful');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2850 assert.equal(automatic.rootTheme, 'auto');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2851 assert.equal(paper.themeLabel, 'Paper');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2852 assert.equal(ink.themeLabel, 'Ink');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2853 assert.equal(playful.themeLabel, 'Playful');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2854 assert.equal(automatic.themeLabel, 'Auto');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2855 for (const sample of [paper, ink, playful, automatic]) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2856 assert.ok(sample.count > 0);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2857 assert.equal(sample.backgroundRepeat, 'no-repeat');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2858 assert.equal(sample.backgroundSize, 'cover');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2859 assert.equal(sample.bodyCoversViewport, true);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2860 assert.equal(sample.componentReady, true);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2861 assert.ok(sample.links > 0);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2862 assert.equal(sample.enhancedLinks, sample.pawLinks);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2863 assert.match(sample.fontFamily, /More/);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2864 assert.equal(sample.headerPaws, 0);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2865 assert.ok(sample.textContrast >= 4.5, JSON.stringify(sample));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2866 assert.equal(sample.mainBackground, 'rgba(0, 0, 0, 0)');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2867 assert.equal(sample.themeButtonBackground, 'rgba(0, 0, 0, 0)');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2868 assert.equal(sample.themeButtonBorder, '0px');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2869 assert.equal(sample.themeButtonShadow, 'none');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2870 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2871 assert.ok(paper.luminance < 175, JSON.stringify(paper));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2872 assert.ok(playful.luminance < 175, JSON.stringify(playful));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2873 assert.ok(ink.luminance > 200, JSON.stringify(ink));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2874 await testThemeCycle(browser);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2875 await testPlainField(browser);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2876 await testButtonScale(browser);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2877 await testDynamicButtonOwnership(browser);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2878 await testResumePrint(browser);
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2879 await testComposerLab(browser);
256
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
2880 }
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2881 if (runsSuite('jrpg')) await testJrpgPage(browser);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2882 if (runsSuite('routing')) await testConversationRouting(browser);
265
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2883 if (runsSuite('greeting')) await testRoleGreetings(browser);
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2884 if (runsSuite('hls')) await testHlsPlayer(browser, siteRoot);
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2885 } finally {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2886 if (browser) await browser.close();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2887 await stopProcess(server);
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
2888 fs.rmSync(tempDirectory, { recursive: true, force: true });
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2889 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2890 })().catch(error => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2891 console.error(error.stack || error);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2892 process.exitCode = 1;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2893 });