annotate mrjunejune/test/theme_and_webp_test.js @ 273:e02e2036ef84 default tip

add Layer 2 JRPG component system Add reusable content and window modals, an isolated component sandbox, shared cyberpunk scroll areas, production-safe cache freshness, and server-rendered JRPG panel state. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Sat, 08 Aug 2026 02:08:08 -0700
parents 41a49c29a28f
children
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
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
494 async function testModalSandbox(browser) {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
495 const context = await browser.newContext({
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
496 serviceWorkers: 'block',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
497 viewport: { width: 1280, height: 900 },
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
498 });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
499 const page = await context.newPage();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
500 const errors = [];
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
501 page.on('pageerror', error => errors.push(error.message));
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
502 page.on('console', message => {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
503 if (message.type() === 'error') errors.push(message.text());
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
504 });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
505 await page.goto(`${baseUrl}/public/component-sandbox.html`, {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
506 waitUntil: 'networkidle',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
507 });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
508 await page.waitForFunction(() =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
509 customElements.get('mjj-content-modal') &&
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
510 customElements.get('mjj-window-modal') &&
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
511 [...document.querySelectorAll('mjj-content-modal, mjj-window-modal')]
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
512 .every(modal => modal.hasAttribute('data-ready'))
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
513 );
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
514 await page.evaluate(() => document.fonts.ready);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
515 const modalCss = await (
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
516 await fetch(`${baseUrl}/public/mjj-modal.css`, { cache: 'no-store' })
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
517 ).text();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
518 assert.match(modalCss, /clip-path:\s*inset\(49% 45%\)/);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
519 assert.match(modalCss, /clip-path:\s*inset\(49% 0\)/);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
520 assert.match(modalCss, /scrollbar-gutter:\s*stable/);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
521
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
522 assert.equal(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
523 await page.locator('mjj-content-modal[data-invalid], mjj-window-modal[data-invalid]')
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
524 .count(),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
525 0,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
526 );
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
527
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
528 await page.getByRole('button', { name: 'Open article' }).click();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
529 const contentDialog = page.locator('mjj-content-modal dialog');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
530 await contentDialog.waitFor({ state: 'visible' });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
531 await contentDialog.evaluate(dialog =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
532 Promise.all(dialog.getAnimations().map(animation => animation.finished))
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
533 );
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
534 const contentMetrics = await contentDialog.evaluate(dialog => {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
535 const body = dialog.querySelector(':scope > [data-modal-body]');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
536 const children = [...dialog.children].map(child => {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
537 if (child.hasAttribute('data-modal-header')) return 'header';
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
538 if (child.hasAttribute('data-modal-body')) return 'body';
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
539 if (child.hasAttribute('data-modal-footer')) return 'footer';
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
540 return child.localName;
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
541 });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
542 const style = getComputedStyle(dialog);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
543 const bodyStyle = getComputedStyle(body);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
544 return {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
545 bodyScrollable: ['auto', 'scroll'].includes(bodyStyle.overflowY),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
546 borderRadius: style.borderRadius,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
547 children,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
548 fontFamily: style.fontFamily,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
549 labelled: dialog.getAttribute('aria-labelledby') ===
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
550 dialog.querySelector('[data-modal-title]').id,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
551 overflowing: body.scrollHeight > body.clientHeight,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
552 shadow: style.boxShadow,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
553 scrollPrimitive: body.localName,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
554 scrollbarColor: bodyStyle.scrollbarColor,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
555 scrollbarGutter: bodyStyle.scrollbarGutter,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
556 width: dialog.getBoundingClientRect().width,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
557 };
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
558 });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
559 assert.deepEqual(contentMetrics.children, ['header', 'body', 'footer']);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
560 assert.equal(contentMetrics.bodyScrollable, true);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
561 assert.equal(contentMetrics.borderRadius, '0px');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
562 assert.equal(contentMetrics.labelled, true);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
563 assert.equal(contentMetrics.fontFamily, '"Pixel Mplus"');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
564 assert.equal(contentMetrics.overflowing, true);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
565 assert.equal(contentMetrics.scrollPrimitive, 'zen-scroll-area');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
566 assert.notEqual(contentMetrics.scrollbarColor, 'auto');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
567 assert.match(contentMetrics.scrollbarGutter, /stable/);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
568 assert.notEqual(contentMetrics.shadow, 'none');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
569 assert.ok(contentMetrics.width <= 864);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
570 await page.getByRole('button', { name: 'Close article' }).click();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
571 await contentDialog.waitFor({ state: 'hidden' });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
572
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
573 await page.getByRole('button', { name: 'Open workspace' }).click();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
574 const windowDialog = page.locator('mjj-window-modal dialog');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
575 await windowDialog.waitFor({ state: 'visible' });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
576 await windowDialog.evaluate(dialog =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
577 Promise.all(dialog.getAnimations().map(animation => animation.finished))
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
578 );
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
579 const windowMetrics = await windowDialog.evaluate(dialog => {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
580 const body = dialog.querySelector(':scope > [data-modal-body]');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
581 const bodyStyle = getComputedStyle(body);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
582 const primary = dialog.querySelector('[data-modal-pane="primary"]');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
583 return {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
584 bodyColumns: bodyStyle.gridTemplateColumns,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
585 bodyScrollable: ['auto', 'scroll'].includes(bodyStyle.overflowY),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
586 borderRadius: getComputedStyle(dialog).borderRadius,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
587 hasStrictRegions:
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
588 Boolean(dialog.querySelector(':scope > [data-modal-header]')) &&
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
589 Boolean(body) &&
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
590 Boolean(dialog.querySelector(':scope > [data-modal-footer]')),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
591 height: dialog.getBoundingClientRect().height,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
592 primaryShadow: getComputedStyle(primary).boxShadow,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
593 primaryOverflowing: primary.scrollHeight > primary.clientHeight,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
594 primaryScrollColor: getComputedStyle(primary).scrollbarColor,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
595 scrollPrimitive: body.localName,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
596 scrollPrimitives:
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
597 dialog.querySelectorAll('zen-scroll-area[data-cyber-scroll]').length,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
598 scrollbarColor: bodyStyle.scrollbarColor,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
599 scrollbarGutter: bodyStyle.scrollbarGutter,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
600 shadow: getComputedStyle(dialog).boxShadow,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
601 };
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
602 });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
603 assert.equal(windowMetrics.bodyScrollable, true);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
604 assert.equal(windowMetrics.borderRadius, '0px');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
605 assert.equal(windowMetrics.hasStrictRegions, true);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
606 assert.equal(windowMetrics.scrollPrimitive, 'zen-scroll-area');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
607 assert.notEqual(windowMetrics.scrollbarColor, 'auto');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
608 assert.match(windowMetrics.scrollbarGutter, /stable/);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
609 assert.match(windowMetrics.bodyColumns, /\d/);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
610 assert.ok(windowMetrics.height <= 768);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
611 assert.notEqual(windowMetrics.primaryShadow, 'none');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
612 assert.equal(windowMetrics.primaryOverflowing, true);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
613 assert.notEqual(windowMetrics.primaryScrollColor, 'auto');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
614 assert.equal(windowMetrics.scrollPrimitives, 3);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
615 assert.notEqual(windowMetrics.shadow, 'none');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
616 await page.getByRole('button', { name: 'Close workspace' }).click();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
617 await windowDialog.waitFor({ state: 'hidden' });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
618 assert.deepEqual(errors, []);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
619 await context.close();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
620
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
621 const mobileContext = await browser.newContext({
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
622 serviceWorkers: 'block',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
623 viewport: { width: 390, height: 844 },
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
624 });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
625 const mobilePage = await mobileContext.newPage();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
626 await mobilePage.goto(`${baseUrl}/public/component-sandbox.html`, {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
627 waitUntil: 'networkidle',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
628 });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
629 await mobilePage.evaluate(() => document.fonts.ready);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
630 await mobilePage.getByRole('button', { name: 'Open workspace' }).click();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
631 const mobileDialog = mobilePage.locator('mjj-window-modal dialog');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
632 await mobileDialog.waitFor({ state: 'visible' });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
633 await mobileDialog.evaluate(dialog =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
634 Promise.all(dialog.getAnimations().map(animation => animation.finished))
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
635 );
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
636 const mobileMetrics = await mobileDialog.evaluate(dialog => {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
637 const body = dialog.querySelector('[data-modal-body]');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
638 const dialogBox = dialog.getBoundingClientRect();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
639 return {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
640 bodyColumns: getComputedStyle(body).gridTemplateColumns,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
641 fits:
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
642 dialogBox.left >= 0 &&
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
643 dialogBox.top >= 0 &&
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
644 dialogBox.right <= innerWidth &&
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
645 dialogBox.bottom <= innerHeight,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
646 pageFits: document.documentElement.scrollWidth <= innerWidth,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
647 };
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
648 });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
649 assert.equal(mobileMetrics.fits, true);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
650 assert.equal(mobileMetrics.pageFits, true);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
651 assert.doesNotMatch(mobileMetrics.bodyColumns, /\s/);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
652 assert.equal(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
653 await mobilePage.locator('mjj-window-modal').getAttribute(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
654 'data-component-layer',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
655 ),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
656 '2',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
657 );
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
658 await mobileContext.close();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
659 }
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
660
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
661 async function testJrpgPage(browser) {
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
662 const context = await browser.newContext({
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
663 colorScheme: 'light',
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
664 viewport: { width: 1280, height: 900 },
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
665 });
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
666 await context.addInitScript(key => {
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
667 sessionStorage.setItem(
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
668 key,
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
669 '00000000-0000-4000-8000-000000000000',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
670 );
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
671 }, 'mjj-jrpg-conversation-id');
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
672 const page = await context.newPage();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
673 const errors = [];
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
674 page.on('pageerror', error => errors.push(`pageerror: ${error.message}`));
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
675 page.on('console', message => {
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
676 if (message.type() === 'error' &&
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
677 !message.text().startsWith('Failed to load resource:')) {
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
678 errors.push(`console: ${message.text()}`);
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
679 }
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
680 });
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
681 page.on('requestfailed', request => {
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
682 if (request.url().startsWith('blob:') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
683 request.failure()?.errorText === 'net::ERR_ABORTED') {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
684 return;
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
685 }
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
686 if (request.method() === 'DELETE' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
687 request.url().includes('/api/download/') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
688 request.failure()?.errorText === 'net::ERR_ABORTED') {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
689 return;
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
690 }
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
691 if (request.method() === 'POST' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
692 request.url().endsWith('/api/latex/render') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
693 request.failure()?.errorText === 'net::ERR_ABORTED') {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
694 return;
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
695 }
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
696 if (request.url().includes('/api/auth/login') &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
697 request.failure()?.errorText === 'net::ERR_ABORTED') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
698 return;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
699 }
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
700 errors.push(`requestfailed: ${request.url()} ${request.failure()?.errorText || ''}`);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
701 });
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
702 page.on('response', response => {
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
703 if (response.status() === 404 &&
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
704 response.url().endsWith(
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
705 '/api/conversations/00000000-0000-4000-8000-000000000000'
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
706 )) {
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
707 return;
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
708 }
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
709 if (response.url().includes('/api/auth/login') && response.status() >= 400) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
710 return; /* expected: login attempt with invalid credentials in modal test */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
711 }
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
712 if (response.status() >= 400) {
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
713 errors.push(`response: ${response.status()} ${response.url()}`);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
714 }
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
715 });
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
716
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
717 for (const expected of [
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
718 { panel: 'resume', title: 'Resume' },
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
719 { panel: 'tools', title: 'Tools' },
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
720 { panel: 'blog', title: 'Blogs' },
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
721 ]) {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
722 const html = await (
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
723 await fetch(`${baseUrl}/jrpg?panel=${expected.panel}`)
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
724 ).text();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
725 assert.match(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
726 html,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
727 new RegExp(`data-initial-panel="${expected.panel}"`),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
728 );
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
729 assert.match(html, new RegExp(`data-preview-title>${expected.title}<`));
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
730 assert.doesNotMatch(html, /__MJJ_[A-Z_]+__/);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
731 }
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
732 const conversationHtml = await (
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
733 await fetch(`${baseUrl}/jrpg?panel=conversations`)
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
734 ).text();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
735 assert.match(conversationHtml, /data-initial-panel="conversations"/);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
736 assert.match(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
737 conversationHtml,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
738 /<mjj-conversation-archive\s+aria-label="Conversations"/,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
739 );
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
740
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
741 await page.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
742 await page.waitForFunction(() =>
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
743 customElements.get('mjj-composer') &&
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
744 customElements.get('mjj-jrpg-menu') &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
745 customElements.get('mjj-jrpg-chat') &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
746 customElements.get('mjj-jrpg-preview')
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
747 );
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
748 await page.waitForFunction(() =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
749 [...document.querySelectorAll('.jrpg-workspace dialog')].every(dialog => {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
750 const owner = dialog.closest('mjj-content-modal, mjj-window-modal');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
751 return owner?.hasAttribute('data-ready');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
752 })
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
753 );
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
754 assert.deepEqual(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
755 await page.evaluate(() =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
756 [...document.querySelectorAll('.jrpg-workspace dialog')]
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
757 .map(dialog =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
758 dialog.closest('mjj-content-modal, mjj-window-modal')?.localName)),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
759 [
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
760 'mjj-window-modal',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
761 'mjj-content-modal',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
762 'mjj-content-modal',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
763 'mjj-window-modal',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
764 'mjj-window-modal',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
765 ],
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
766 'every JRPG dialog has a Layer 2 owner',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
767 );
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
768 await page.evaluate(() => document.fonts.ready);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
769 const desktop = await page.evaluate(() => {
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
770 const scene = document.querySelector('.jrpg-scene').getBoundingClientRect();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
771 const utility = document.querySelector('.jrpg-utility').getBoundingClientRect();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
772 const composer = document.querySelector('mjj-composer')
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
773 .getBoundingClientRect();
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
774 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
775 .getBoundingClientRect();
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
776 const composerFieldStyle = getComputedStyle(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
777 document.querySelector('.jrpg-composer zen-field'),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
778 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
779 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
780 .getBoundingClientRect();
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
781 const composerTextarea = document.querySelector('#jrpg-message')
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
782 .getBoundingClientRect();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
783 const menuElement = document.querySelector('mjj-jrpg-menu');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
784 const menu = menuElement.getBoundingClientRect();
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
785 const character = document.querySelector('[data-character]');
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
786 const epiAvatar = document.querySelector(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
787 '.jrpg-message[data-speaker="Epi"] .jrpg-message-avatar',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
788 );
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
789 const characterBox = character.getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
790 const sceneBarStyle = getComputedStyle(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
791 document.querySelector('.jrpg-scene'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
792 '::before',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
793 );
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
794 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
795 .getBoundingClientRect();
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
796 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
797 .getBoundingClientRect();
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
798 const workspace = document.querySelector('.jrpg-workspace')
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
799 .getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
800 const brand = document.querySelector('.jrpg-brand').getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
801 const frameControls = document.querySelector('.jrpg-frame-controls')
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
802 .getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
803 const frameTelemetry = document.querySelector('.jrpg-frame-telemetry')
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
804 .getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
805 const telemetryValues = [
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
806 ...document.querySelectorAll('.jrpg-frame-telemetry > *'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
807 ].map(value => value.getBoundingClientRect());
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
808 const shell = document.querySelector('.jrpg-shell').getBoundingClientRect();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
809 const main = document.querySelector('.jrpg-main').getBoundingClientRect();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
810 const colorProbe = document.createElement('span');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
811 colorProbe.style.background = 'var(--zenbu-sys-color-surface-page)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
812 colorProbe.style.color =
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
813 'var(--zenbu-sys-color-action-primary-background)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
814 colorProbe.style.borderColor = 'var(--zenbu-sys-color-focus-outer)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
815 const surfaceProbe = document.createElement('span');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
816 surfaceProbe.style.background =
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
817 'var(--zenbu-sys-color-surface-default)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
818 surfaceProbe.style.color = 'var(--zenbu-sys-color-text-primary)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
819 surfaceProbe.style.borderColor = 'var(--zenbu-sys-color-border-strong)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
820 const sunkenProbe = document.createElement('span');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
821 sunkenProbe.style.background =
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
822 'var(--zenbu-sys-color-surface-sunken)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
823 const panelProbe = document.createElement('span');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
824 panelProbe.style.background = 'var(--mjj-jrpg-panel-strong)';
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
825 document.body.append(colorProbe, surfaceProbe, sunkenProbe, panelProbe);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
826 const probeStyle = getComputedStyle(colorProbe);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
827 const surfaceProbeStyle = getComputedStyle(surfaceProbe);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
828 const sunkenProbeStyle = getComputedStyle(sunkenProbe);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
829 const panelProbeStyle = getComputedStyle(panelProbe);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
830 const computedFonts = [
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
831 document.body,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
832 document.querySelector('.jrpg-brand h1'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
833 document.querySelector('.jrpg-message p'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
834 document.querySelector('#jrpg-message'),
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
835 document.querySelector('.jrpg-composer button[type="submit"]'),
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
836 ].map(element => getComputedStyle(element).fontFamily);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
837 const nonPixelText = [document.body, ...document.body.querySelectorAll('*')]
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
838 .filter(element => [...element.childNodes].some(node =>
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
839 node.nodeType === Node.TEXT_NODE && node.textContent.trim()
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
840 ))
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
841 .filter(element =>
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
842 getComputedStyle(element).fontFamily !== '"Pixel Mplus"'
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
843 )
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
844 .map(element => element.localName);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
845 const pageStyle = getComputedStyle(document.body);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
846 const submitStyle = getComputedStyle(
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
847 document.querySelector('.jrpg-composer button[type="submit"]'),
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
848 );
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
849 const colors = {
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
850 canvas: probeStyle.backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
851 conversation: getComputedStyle(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
852 document.querySelector('mjj-jrpg-chat'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
853 ).backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
854 conversationBorder: getComputedStyle(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
855 document.querySelector('mjj-jrpg-chat'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
856 ).borderTopColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
857 conversationPanel: panelProbeStyle.backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
858 conversationText: getComputedStyle(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
859 document.querySelector('.jrpg-message p'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
860 ).color,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
861 focus: probeStyle.borderColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
862 frame: surfaceProbeStyle.borderColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
863 menu: getComputedStyle(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
864 document.querySelector('mjj-jrpg-menu'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
865 ).backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
866 page: pageStyle.backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
867 primary: probeStyle.color,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
868 primaryText: getComputedStyle(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
869 document.querySelector('.jrpg-preview-panel h2'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
870 ).color,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
871 sunken: sunkenProbeStyle.backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
872 surface: surfaceProbeStyle.backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
873 submit: submitStyle.backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
874 text: surfaceProbeStyle.color,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
875 utility: getComputedStyle(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
876 document.querySelector('.jrpg-utility'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
877 ).backgroundColor,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
878 };
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
879 colorProbe.remove();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
880 surfaceProbe.remove();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
881 sunkenProbe.remove();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
882 panelProbe.remove();
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
883 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
884 const frameAlignment = [
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
885 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
886 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
887 closeTo(scene.width / workspace.width, 0.548),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
888 closeTo(scene.height / workspace.height, 0.57),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
889 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
890 closeTo(utility.width / workspace.width, 0.365),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
891 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
892 closeTo(composer.width / workspace.width, 0.682),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
893 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
894 closeTo(menu.width / workspace.width, 0.234),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
895 ].every(Boolean);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
896 const borderless = [
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
897 '.jrpg-shell',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
898 '.jrpg-scene',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
899 '.jrpg-utility',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
900 'mjj-jrpg-chat',
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
901 'mjj-composer',
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
902 'mjj-jrpg-menu',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
903 '.jrpg-preview-panel',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
904 '.jrpg-message',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
905 '.jrpg-work-showcase a',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
906 'mjj-jrpg-menu button',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
907 ].every(selector => {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
908 const style = getComputedStyle(document.querySelector(selector));
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
909 return style.borderTopWidth === '0px' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
910 style.borderRightWidth === '0px' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
911 style.borderBottomWidth === '0px' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
912 style.borderLeftWidth === '0px';
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
913 });
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
914 return {
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
915 art: getComputedStyle(document.querySelector('.jrpg-workspace'))
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
916 .backgroundImage,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
917 borderless,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
918 brandInSystemSlot:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
919 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
920 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
921 document.querySelector('.jrpg-brand').parentElement.classList
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
922 .contains('jrpg-workspace'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
923 brandCoversSystemLabel:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
924 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
925 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
926 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
927 brand.bottom >= workspace.top + workspace.height * 0.06,
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
928 characterLoaded: character.complete && character.naturalWidth > 0,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
929 epiAvatarLoaded:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
930 epiAvatar?.complete &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
931 epiAvatar.naturalWidth > 0 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
932 epiAvatar.getAttribute('aria-hidden') === 'true',
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
933 colors,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
934 composerBelowScene: composer.top >= scene.bottom,
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
935 composerTextareaFills: (
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
936 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
937 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
938 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
939 composerTextarea.height > 60
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
940 ),
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
941 composerUsesZenStyles:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
942 getComputedStyle(document.querySelector('.jrpg-composer textarea'))
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
943 .borderTopWidth !== '0px' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
944 submitStyle.borderTopWidth !== '0px',
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
945 composerTextareaGeometry: {
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
946 fieldBottom: composerField.bottom,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
947 fieldDisplay: composerFieldStyle.display,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
948 fieldGridRows: composerFieldStyle.gridTemplateRows,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
949 fieldLeft: composerField.left,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
950 fieldRight: composerField.right,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
951 fieldTop: composerField.top,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
952 labelBottom: composerLabel.bottom,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
953 labelTop: composerLabel.top,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
954 textareaBottom: composerTextarea.bottom,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
955 textareaHeight: composerTextarea.height,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
956 textareaLeft: composerTextarea.left,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
957 textareaRight: composerTextarea.right,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
958 textareaTop: composerTextarea.top,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
959 },
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
960 fillsViewport: shell.left === 0 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
961 shell.top === 0 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
962 Math.abs(shell.right - innerWidth) < 1 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
963 Math.abs(shell.bottom - innerHeight) < 1 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
964 main.left === 0 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
965 main.top === 0 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
966 Math.abs(main.right - innerWidth) < 1 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
967 Math.abs(main.bottom - innerHeight) < 1,
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
968 frameAlignment,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
969 frameChromeAligned:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
970 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
971 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
972 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
973 fonts: computedFonts,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
974 fontLoaded: [...document.fonts].some(font =>
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
975 font.family.replaceAll('"', '') === 'Pixel Mplus' &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
976 font.status === 'loaded'
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
977 ),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
978 menuRightOfComposer: menu.left >= composer.right,
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
979 messageViewportFills: (
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
980 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
981 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
982 messageViewport.height > 192
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
983 ),
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
984 noOverflow: document.documentElement.scrollWidth <= innerWidth,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
985 nonPixelText,
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
986 questLabelAbsent: !document.body.textContent.includes('QUEST 01'),
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
987 previewLabelsRemoved:
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
988 !/CHARACTER RECORD|ITEM INVENTORY|QUEST ARCHIVE/.test(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
989 document.querySelector('.jrpg-preview-panel').textContent,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
990 ),
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
991 statsRemoved:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
992 !document.querySelector('.jrpg-preview-stats') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
993 !document.querySelector('[data-preview-type]'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
994 telemetryCovered:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
995 document.querySelectorAll('.jrpg-frame-telemetry > *').length === 4 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
996 document.querySelector('[data-frame-network]').textContent
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
997 .includes('ONLINE') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
998 document.querySelector('[data-frame-uptime]').textContent
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
999 .match(/^\d{2}:\d{2}:\d{2}$/) &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1000 [...document.querySelectorAll('.jrpg-frame-telemetry > *')]
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1001 .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
1002 telemetryValuesAligned:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1003 closeTo(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1004 (telemetryValues[0].left + telemetryValues[0].width / 2 -
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1005 frameTelemetry.left) / frameTelemetry.width,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1006 0.12,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1007 ) &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1008 closeTo(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1009 (telemetryValues[1].left + telemetryValues[1].width / 2 -
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1010 frameTelemetry.left) / frameTelemetry.width,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1011 0.325,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1012 ) &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1013 closeTo(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1014 (telemetryValues[2].left + telemetryValues[2].width / 2 -
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1015 frameTelemetry.left) / frameTelemetry.width,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1016 0.605,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1017 ) &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1018 closeTo(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1019 (telemetryValues[3].left + telemetryValues[3].width / 2 -
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1020 frameTelemetry.left) / frameTelemetry.width,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1021 0.88,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1022 ),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1023 shibaInFrontOfBar:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1024 sceneBarStyle.backgroundImage.includes('bar-ink.webp') &&
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1025 sceneBarStyle.backgroundSize === 'cover' &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1026 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
1027 Number(getComputedStyle(character.parentElement).zIndex) >
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1028 Number(sceneBarStyle.zIndex) &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1029 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
1030 terminalScrollbar: (
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1031 getComputedStyle(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1032 document.querySelector('.jrpg-message-viewport'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1033 ).scrollbarWidth === 'thin' &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1034 getComputedStyle(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1035 document.querySelector('.jrpg-message-viewport'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1036 ).scrollbarColor !== 'auto'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1037 ),
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1038 theme: document.documentElement.dataset.zenTheme,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1039 utilityRightOfScene: utility.left >= scene.right,
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1040 workspaceFillsViewport:
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1041 Math.abs(workspace.left) < 1 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1042 Math.abs(workspace.top) < 1 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1043 Math.abs(workspace.right - innerWidth) < 1 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1044 Math.abs(workspace.bottom - innerHeight) < 1,
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1045 };
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1046 });
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1047 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
1048 assert.equal(desktop.borderless, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1049 assert.equal(desktop.brandInSystemSlot, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1050 assert.equal(desktop.brandCoversSystemLabel, true);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1051 assert.equal(desktop.characterLoaded, true);
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1052 assert.equal(desktop.epiAvatarLoaded, true);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1053 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
1054 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
1055 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
1056 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
1057 assert.equal(desktop.colors.primaryText, desktop.colors.primary);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1058 assert.equal(desktop.colors.submit, desktop.colors.primary);
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1059 assert.equal(desktop.composerUsesZenStyles, true);
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1060 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
1061 assert.equal(desktop.composerBelowScene, true);
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1062 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1063 desktop.composerTextareaFills,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1064 true,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1065 JSON.stringify(desktop.composerTextareaGeometry),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1066 );
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1067 assert.equal(desktop.fillsViewport, true);
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1068 assert.equal(desktop.frameAlignment, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1069 assert.equal(desktop.frameChromeAligned, true);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1070 assert.ok(desktop.fonts.every(font => font === '"Pixel Mplus"'));
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1071 assert.equal(desktop.fontLoaded, true);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1072 assert.equal(desktop.menuRightOfComposer, true);
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1073 assert.equal(desktop.messageViewportFills, true);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1074 assert.equal(desktop.noOverflow, true);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1075 assert.deepEqual(desktop.nonPixelText, []);
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1076 assert.equal(desktop.questLabelAbsent, true);
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1077 assert.equal(desktop.previewLabelsRemoved, true);
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1078 assert.equal(desktop.statsRemoved, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1079 assert.equal(desktop.telemetryCovered, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1080 assert.equal(desktop.telemetryValuesAligned, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1081 assert.equal(desktop.shibaInFrontOfBar, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1082 assert.equal(desktop.terminalScrollbar, true);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1083 assert.equal(desktop.theme, 'cyberpunk');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1084 assert.equal(desktop.utilityRightOfScene, true);
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1085 assert.equal(desktop.workspaceFillsViewport, true);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1086 await page.locator('.jrpg-brand a').focus();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1087 assert.equal(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1088 await page.locator('.jrpg-brand a').evaluate(element =>
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1089 getComputedStyle(element).outlineColor
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1090 ),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1091 desktop.colors.focus,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1092 );
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
1093 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
1094 assert.equal(
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
1095 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
1096 getComputedStyle(element).outlineColor
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1097 ),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1098 desktop.colors.focus,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1099 );
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1100 assert.equal(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1101 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
1102 desktop.colors.canvas,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1103 );
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1104 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1105 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
1106 3,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1107 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1108 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1109 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
1110 '/',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1111 );
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1112
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1113 // Account slot: guest session shows a login button (modal trigger)
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1114 assert.ok(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1115 await page.locator('[data-frame-account]').count() > 0,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1116 'account slot exists in telemetry',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1117 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1118 await page.waitForFunction(() =>
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1119 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
1120 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1121 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
1122 text: btn.textContent.trim(),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1123 ownerCount: btn.closest('zen-button') ? 1 : 0,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1124 appearance: btn.closest('zen-button')?.getAttribute('appearance'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1125 size: btn.closest('zen-button')?.getAttribute('size'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1126 }));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1127 assert.match(loginBtnState.text, /LOGIN/i);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1128 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
1129 assert.equal(loginBtnState.appearance, 'plain');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1130 assert.equal(loginBtnState.size, 'xs');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1131
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1132 // 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
1133 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
1134 await page.locator('[data-login-dialog]').waitFor({ state: 'visible' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1135 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1136 await page.locator('[data-login-dialog]').getAttribute('aria-modal'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1137 'true',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1138 'login dialog is modal',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1139 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1140 // Username input should receive initial focus
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1141 await page.waitForFunction(() => document.activeElement?.id === 'jrpg-login-username');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1142 // Cancel closes dialog and clears password
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1143 await page.locator('#jrpg-login-password').fill('dummypassword');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1144 await page.locator('[data-login-cancel]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1145 await page.locator('[data-login-dialog]').waitFor({ state: 'hidden' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1146 await page.waitForFunction(() => !document.querySelector('#jrpg-login-password')?.value);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1147 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1148 await page.locator('#jrpg-login-password').inputValue(),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1149 '',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1150 'password cleared on close',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1151 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1152
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1153 // Invalid credentials show error message
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1154 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
1155 await page.locator('[data-login-dialog]').waitFor({ state: 'visible' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1156 await page.locator('#jrpg-login-username').fill('nosuchuser');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1157 await page.locator('#jrpg-login-password').fill('nosuchpassword123');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1158 let loginErrorShown = false;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1159 const loginResponsePromise = page.waitForResponse(resp =>
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1160 resp.url().includes('/api/auth/login')
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1161 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1162 await page.locator('[data-login-submit]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1163 const loginResp = await loginResponsePromise;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1164 if (loginResp.status() >= 400) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1165 await page.waitForFunction(() => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1166 const el = document.querySelector('[data-login-error]');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1167 return el && !el.hidden && el.textContent.trim().length > 0;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1168 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1169 loginErrorShown = true;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1170 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1171 assert.equal(loginErrorShown, true, 'error element shown on bad credentials');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1172 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1173 await page.locator('#jrpg-login-password').inputValue(),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1174 '',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1175 'password cleared after failed login attempt',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1176 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1177 // Close modal via X button (data-zen-close)
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1178 await page.getByRole('button', { name: 'Close sign-in dialog' }).click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1179 await page.locator('[data-login-dialog]').waitFor({ state: 'hidden' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1180
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1181 // Archive opens only from the bottom destination menu.
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1182 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1183 await page.locator('[data-toggle-archive]').count(),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1184 0,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1185 'redundant chat-heading archive shortcut is removed',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1186 );
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1187 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1188 await page.locator('.jrpg-panel-heading').count(),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1189 0,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1190 'visible conversation heading is removed',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1191 );
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1192 await page.locator('button[data-preview="conversations"]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1193 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
1194 const archiveGeometry = await page.evaluate(() => {
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1195 const utilityElement = document.querySelector('.jrpg-utility');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1196 const archiveElement = utilityElement.querySelector('mjj-conversation-archive');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1197 const utility = utilityElement.getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1198 const archive = archiveElement.getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1199 const archiveStyle = getComputedStyle(archiveElement);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1200 const previewPanel = utilityElement.querySelector('.jrpg-preview-panel');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1201 const panel = previewPanel.getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1202 const previewPanelStyle = getComputedStyle(previewPanel);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1203 const panelPadding = {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1204 bottom: parseFloat(previewPanelStyle.paddingBottom),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1205 left: parseFloat(previewPanelStyle.paddingLeft),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1206 right: parseFloat(previewPanelStyle.paddingRight),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1207 top: parseFloat(previewPanelStyle.paddingTop),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1208 };
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1209 const previewContent = previewPanel.querySelector('[data-preview-content]');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1210 const renderedPanelChildren = Array.from(previewPanel.children)
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1211 .filter(element => getComputedStyle(element).display !== 'none')
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1212 .map(element => element.localName);
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1213 return {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1214 archive: {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1215 bottom: archive.bottom,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1216 height: archive.height,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1217 left: archive.left,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1218 right: archive.right,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1219 top: archive.top,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1220 width: archive.width,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1221 },
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1222 fits: Math.abs(archive.left - panel.left - panelPadding.left) < 1 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1223 Math.abs(archive.top - panel.top - panelPadding.top) < 1 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1224 Math.abs(panel.right - panelPadding.right - archive.right) < 1 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1225 Math.abs(panel.bottom - panelPadding.bottom - archive.bottom) < 1,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1226 integrated: archiveStyle.position === 'static' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1227 archiveStyle.zIndex === 'auto' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1228 archiveStyle.backgroundColor === 'rgba(0, 0, 0, 0)' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1229 archiveStyle.backgroundImage === 'none' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1230 archiveStyle.boxShadow === 'none' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1231 previewPanelStyle.display === 'block' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1232 archiveElement.parentElement === previewPanel &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1233 previewContent.hidden &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1234 renderedPanelChildren.length === 1 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1235 renderedPanelChildren[0] === 'mjj-conversation-archive',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1236 renderedPanelChildren,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1237 panel: {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1238 bottom: panel.bottom,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1239 height: panel.height,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1240 left: panel.left,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1241 right: panel.right,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1242 top: panel.top,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1243 width: panel.width,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1244 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1245 panelPadding,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1246 utility: {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1247 bottom: utility.bottom,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1248 height: utility.height,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1249 left: utility.left,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1250 right: utility.right,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1251 top: utility.top,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1252 width: utility.width,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1253 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1254 };
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1255 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1256 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1257 archiveGeometry.fits,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1258 true,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1259 `conversation archive fills the existing utility content panel: ${JSON.stringify(archiveGeometry)}`,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1260 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1261 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1262 archiveGeometry.integrated,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1263 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1264 `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
1265 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1266 // Archive status or empty message should be visible
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1267 await page.waitForFunction(() => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1268 const status = document.querySelector('[data-archive-status]');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1269 return status && !status.hidden;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1270 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1271 // New conversation button exists inside archive
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1272 assert.ok(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1273 await page.locator('[data-archive-new]').isVisible(),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1274 'archive new button visible',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1275 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1276 // Conversations menu button should be pressed
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1277 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1278 await page.locator('button[data-preview="conversations"]').getAttribute('aria-pressed'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1279 'true',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1280 );
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1281 await page.evaluate(() => {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1282 document.querySelector('mjj-conversation-archive')?.addConversation({
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1283 id: 'eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1284 title: 'Modal migration fixture',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1285 turn_count: 2,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1286 });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1287 });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1288 await page.getByRole('button', {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1289 name: 'Rename "Modal migration fixture"',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1290 }).click();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1291 await page.locator('[data-archive-rename-dialog]').waitFor({ state: 'visible' });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1292 assert.equal(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1293 await page.locator('[data-archive-rename-dialog]').evaluate(dialog =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1294 dialog.closest('mjj-window-modal')?.localName),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1295 'mjj-window-modal',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1296 );
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1297 await page.locator('[data-archive-rename-cancel]').click();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1298 await page.locator('[data-archive-rename-dialog]').waitFor({ state: 'hidden' });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1299
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1300 await page.getByRole('button', {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1301 name: 'Delete "Modal migration fixture"',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1302 }).click();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1303 await page.locator('[data-archive-delete-dialog]').waitFor({ state: 'visible' });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1304 assert.equal(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1305 await page.locator('[data-archive-delete-dialog]').evaluate(dialog =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1306 dialog.closest('mjj-content-modal')?.localName),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1307 'mjj-content-modal',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1308 );
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1309 await page.locator('[data-archive-delete-cancel]').click();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1310 await page.locator('[data-archive-delete-dialog]').waitFor({ state: 'hidden' });
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1311
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1312 // Archive: close via close button, navigates back to resume panel
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1313 await page.locator('[data-archive-close]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1314 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
1315 // mjj-jrpg-chat must remain visible (always in scene)
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1316 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1317 await page.locator('mjj-jrpg-chat').isVisible(),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1318 true,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1319 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1320
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1321 // Quota element is present (may be shown for guest session)
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1322 assert.ok(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1323 await page.locator('[data-quota]').count() > 0,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1324 'quota element exists',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1325 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1326
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1327 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
1328 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1329 await page.locator('.jrpg-scene').evaluate(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1330 scene => getComputedStyle(scene).visibility,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1331 ),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1332 'hidden',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1333 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1334 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
1335 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1336 await page.locator('.jrpg-scene').evaluate(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1337 scene => getComputedStyle(scene).visibility,
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 'visible',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1340 );
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1341 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
1342 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1343 await page.getByRole('button', { name: /Inspect/ }).count(),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1344 0,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1345 );
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1346 assert.match(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1347 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
1348 /Copilot Tasks/,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1349 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1350 assert.match(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1351 await page.locator('[data-work-showcase]').textContent(),
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1352 /AIX Harness \/ Copilot/,
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1353 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1354 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1355 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
1356 'START',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1357 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1358 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1359 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
1360 true,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1361 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1362 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1363 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
1364 true,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1365 );
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1366
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1367 await page.getByRole('button', { name: 'Tools', exact: true }).click();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1368 assert.equal(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1369 await page.locator('[data-preview-title]').textContent(),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1370 'Tools',
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1371 );
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1372 assert.equal(await page.locator('[data-preview-link]').count(), 0);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1373 assert.equal(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1374 await page.getByRole('button', { name: 'Tools', exact: true })
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1375 .getAttribute('aria-pressed'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1376 'true',
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1377 );
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1378 await page.waitForFunction(() =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1379 document.querySelectorAll('[data-latest-tool]').length === 5
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1380 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1381 assert.match(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1382 await page.locator('[data-work-showcase]').textContent(),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1383 /Online LaTeX Editor/,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1384 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1385 assert.match(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1386 await page.locator('[data-work-showcase]').textContent(),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1387 /Personal Notes/,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1388 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1389 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
1390 await page.locator('[data-functional-tool="markdown"]').waitFor();
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1391 assert.equal(
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1392 await page.locator('.jrpg-detail-dialog').evaluate(dialog =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1393 dialog.closest('mjj-content-modal, mjj-window-modal')?.localName),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1394 'mjj-window-modal',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1395 'tool details use the window modal',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1396 );
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1397 assert.equal(
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1398 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
1399 'MarkDown to HTML',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1400 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1401 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
1402 await page.waitForFunction(() =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1403 document.querySelector('[data-markdown-output] h1')?.textContent ===
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1404 'Modal Markdown'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1405 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1406 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
1407 const toolWorkspace = await page.evaluate(() => {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1408 const dialogElement = document.querySelector(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1409 '.jrpg-detail-dialog[data-detail-mode="tools"]',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1410 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1411 const dialog = dialogElement.getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1412 const windows = [...document.querySelectorAll('.jrpg-tool-window')]
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1413 .map(window => window.getBoundingClientRect());
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1414 const windowShadows = [...document.querySelectorAll('.jrpg-tool-window')]
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1415 .map(window => getComputedStyle(window).boxShadow);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1416 return {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1417 dialogHeight: dialogElement.offsetHeight,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1418 dialogWidth: dialogElement.offsetWidth,
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1419 compact: dialogElement.offsetWidth <= innerWidth * 0.9 &&
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1420 dialogElement.offsetHeight <= innerHeight * 0.8,
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1421 viewportHeight: innerHeight,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1422 viewportWidth: innerWidth,
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1423 stacked: windows.length === 2 &&
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1424 windows[0].bottom < windows[1].top &&
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1425 Math.abs(windows[0].left - windows[1].left) < 1,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1426 noOpenPageAction: !document.querySelector('[data-preview-link]'),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1427 noFooter: !document.querySelector('[data-dialog-actions]'),
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1428 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
1429 [...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
1430 .every(icon =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1431 getComputedStyle(icon).shapeRendering.toLowerCase() === 'crispedges'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1432 ),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1433 separateGlows: windowShadows.length === 2 &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1434 windowShadows.every(shadow => shadow !== 'none'),
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1435 wideWindows: windows.every(window => window.width > dialog.width * 0.8),
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1436 };
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1437 });
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1438 assert.equal(toolWorkspace.compact, true, JSON.stringify(toolWorkspace));
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1439 assert.equal(toolWorkspace.stacked, true);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1440 assert.equal(toolWorkspace.noOpenPageAction, true);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1441 assert.equal(toolWorkspace.noFooter, true);
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1442 assert.equal(toolWorkspace.pixelIcons, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1443 assert.equal(toolWorkspace.separateGlows, true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1444 assert.equal(toolWorkspace.wideWindows, true);
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1445 await page.locator('.jrpg-detail-dialog').evaluate(dialog =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1446 Promise.all(dialog.getAnimations().map(animation => animation.finished))
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1447 );
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1448 await page.getByRole('button', {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1449 name: 'Close destination details',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1450 }).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1451 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
1452
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1453 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
1454 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
1455 await page.getByRole('button', {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1456 name: 'Close destination details',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1457 }).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1458 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
1459
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1460 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
1461 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
1462 assert.equal(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1463 await page.locator('[data-converter-input]').count(),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1464 2,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1465 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1466 const converterFixture = path.join(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1467 RUNFILES,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1468 WORKSPACE,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1469 'mrjunejune/test/shiba.webp',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1470 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1471 assert.equal(fs.existsSync(converterFixture), true);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1472 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
1473 converterFixture,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1474 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1475 const conversionResponse = page.waitForResponse(response =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1476 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
1477 response.request().method() === 'POST'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1478 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1479 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
1480 assert.equal((await conversionResponse).status(), 200);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1481 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
1482 const cleanupResponse = page.waitForResponse(response =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1483 response.url().includes('/api/download/') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1484 response.request().method() === 'DELETE'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1485 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1486 await page.getByRole('button', {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1487 name: 'Close destination details',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1488 }).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1489 assert.equal((await cleanupResponse).status(), 204);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1490 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
1491
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1492 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
1493 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
1494 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
1495 converterFixture,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1496 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1497 const lateConversionResponse = page.waitForResponse(response =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1498 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
1499 response.request().method() === 'POST'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1500 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1501 const lateCleanupResponse = page.waitForResponse(response =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1502 response.url().includes('/api/download/') &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1503 response.request().method() === 'DELETE'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1504 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1505 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
1506 await page.getByRole('button', {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1507 name: 'Close destination details',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1508 }).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1509 assert.equal((await lateConversionResponse).status(), 200);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1510 assert.equal((await lateCleanupResponse).status(), 204);
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1511 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
1512
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1513 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
1514 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
1515 await page.locator('[data-hls-sample]').click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1516 await page.waitForFunction(() =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1517 ['ready', 'error'].includes(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1518 document.querySelector('[data-hls-status]')?.dataset.state,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1519 )
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1520 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1521 assert.ok(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1522 ['ready', 'error'].includes(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1523 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
1524 ),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1525 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1526 assert.match(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1527 await page.locator('[data-hls-status]').textContent(),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1528 /ready|unsupported|failed/i,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1529 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1530 await page.getByRole('button', {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1531 name: 'Close destination details',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1532 }).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1533 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
1534
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1535 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
1536 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
1537 await page.locator('[data-latex-compile]').click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1538 await page.locator('[data-latex-source]').fill(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1539 '\\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
1540 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1541 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
1542 await page.locator('[data-latex-compile]').click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1543 await page.waitForFunction(() =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1544 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
1545 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1546 assert.match(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1547 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
1548 /^blob:/,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1549 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1550 await page.getByRole('button', {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1551 name: 'Close destination details',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1552 }).click();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1553 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
1554
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1555 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
1556 await page.waitForFunction(() =>
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1557 document.querySelector('[data-tool-content] h1')?.textContent ===
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1558 'Personal Notes'
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1559 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1560 assert.match(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1561 await page.locator('[data-tool-content]').textContent(),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1562 /private browser-based writing workspace/,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1563 );
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1564 await page.getByRole('button', {
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1565 name: 'Close destination details',
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1566 }).click();
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1567 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
1568
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1569 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
1570 await page.locator('[data-resume-modal]').click();
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1571 assert.equal(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1572 await page.locator('.jrpg-detail-dialog').evaluate(dialog =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1573 dialog.closest('mjj-content-modal, mjj-window-modal')?.localName),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1574 'mjj-content-modal',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1575 'resume details use the content modal',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1576 );
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1577 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
1578 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
1579 dossier => ({
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1580 fontFamily: getComputedStyle(dossier).fontFamily,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1581 text: dossier.textContent,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1582 }),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1583 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1584 assert.equal(resumeDossier.fontFamily, '"Pixel Mplus"');
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1585 assert.match(resumeDossier.text, /Copilot Tasks/);
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1586 assert.match(resumeDossier.text, /Microsoft/);
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1587 assert.match(resumeDossier.text, /Meta/);
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1588 const resumeModalGeometry = await page.locator('.jrpg-detail-dialog').evaluate(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1589 dialog => {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1590 const body = dialog.querySelector('[data-modal-body]').getBoundingClientRect();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1591 const dossier = dialog.querySelector('[data-resume-dossier]')
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1592 .getBoundingClientRect();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1593 const buttons = [...dialog.querySelectorAll(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1594 '[data-modal-header] zen-button > :is(button, a)',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1595 )].map(control => control.getBoundingClientRect());
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1596 return {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1597 bodyFilled:
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1598 dossier.width / body.width > 0.9 &&
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1599 Math.abs(dossier.left - body.left) < 32,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1600 equalHeaderControls:
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1601 buttons.length === 2 &&
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1602 Math.abs(buttons[0].height - buttons[1].height) < 1,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1603 headerControlHeights: buttons.map(button => button.height),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1604 footerAbsent: !dialog.querySelector('[data-modal-footer]'),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1605 headerPdfLinks: dialog.querySelectorAll(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1606 '[data-modal-header] a[href="/public/resume.pdf"]',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1607 ).length,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1608 visibleBodyPdfLinks: [...dialog.querySelectorAll(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1609 '[data-modal-body] a[href="/public/resume.pdf"]',
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1610 )].filter(link => getComputedStyle(link).display !== 'none').length,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1611 pdfLinks: dialog.querySelectorAll('a[href="/public/resume.pdf"]').length,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1612 };
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1613 },
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1614 );
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1615 assert.equal(resumeModalGeometry.bodyFilled, true);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1616 assert.equal(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1617 resumeModalGeometry.equalHeaderControls,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1618 true,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1619 JSON.stringify(resumeModalGeometry),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1620 );
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1621 assert.equal(resumeModalGeometry.footerAbsent, true);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1622 assert.equal(resumeModalGeometry.headerPdfLinks, 1);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1623 assert.equal(resumeModalGeometry.visibleBodyPdfLinks, 0);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1624 assert.equal(resumeModalGeometry.pdfLinks, 1);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1625 await page.locator('.jrpg-detail-dialog').evaluate(dialog =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1626 Promise.all(dialog.getAnimations().map(animation => animation.finished))
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1627 );
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1628 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1629 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
1630 true,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1631 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1632 await page.getByRole('button', {
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1633 name: 'Close destination details',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1634 }).click();
262
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1635 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
1636
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1637 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
1638 await page.waitForFunction(() =>
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1639 document.querySelectorAll('[data-latest-blog]').length === 4
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1640 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1641 assert.match(
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1642 await page.locator('[data-work-showcase]').textContent(),
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1643 /Websocket Demystified/,
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1644 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1645 assert.match(
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1646 await page.locator('[data-work-showcase]').textContent(),
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1647 /Creating Network Library in C/,
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1648 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1649 await page.locator('[data-latest-blog]').first().click();
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1650 await page.locator('[data-blog-content] h1').waitFor();
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1651 assert.equal(
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1652 await page.locator('[data-blog-content] h1').textContent(),
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1653 'WebSocket Demystified',
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1654 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1655 assert.equal(
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1656 await page.locator('[data-blog-content]').evaluate(
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1657 article => getComputedStyle(article).fontFamily,
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1658 ),
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1659 '"Pixel Mplus"',
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1660 );
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1661 const blogWidth = await page.locator('.jrpg-detail-dialog').evaluate(dialog => {
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1662 const body = dialog.querySelector('[data-modal-body]').getBoundingClientRect();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1663 const browser = dialog.querySelector('[data-blog-browser]')
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1664 .getBoundingClientRect();
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1665 return browser.width / body.width;
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1666 });
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1667 assert.ok(blogWidth > 0.9);
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1668 await page.locator('.jrpg-detail-dialog').evaluate(dialog =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1669 Promise.all(dialog.getAnimations().map(animation => animation.finished))
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1670 );
262
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1671 await page.getByRole('button', {
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1672 name: 'Close destination details',
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1673 }).click();
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1674 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
1675
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1676 await page.locator('[data-blog-archive]').click();
262
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1677 await page.waitForFunction(() =>
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1678 document.querySelectorAll('[data-blog-entry]').length === 9
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1679 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1680 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
1681 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
1682 await page.waitForFunction(() =>
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1683 document.querySelector('[data-blog-content] h1')?.textContent ===
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1684 'Creating Network Library in C'
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1685 );
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1686 await page.getByRole('button', {
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1687 name: 'Close destination details',
0f45474c1b1a Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 261
diff changeset
1688 }).click();
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1689
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1690 await page.evaluate(() => {
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1691 window.__jrpgStreamEvents = [];
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1692 document.querySelector('mjj-jrpg-shell').addEventListener(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1693 'mjj-jrpg-stream-event',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1694 event => window.__jrpgStreamEvents.push(event.detail),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1695 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1696 });
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1697 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
1698 await page.locator('#jrpg-message').press('Enter');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1699 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
1700 const streamingMessage = page.locator(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1701 '.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
1702 ).last();
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1703 await streamingMessage.waitFor();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1704 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
1705 await streamingMessage.waitFor();
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1706 assert.notEqual(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1707 await streamingMessage.locator('p').textContent(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1708 'hello traveler',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1709 );
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1710 await page.getByRole('button', { name: 'Blogs', exact: true }).click();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1711 assert.equal(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1712 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
1713 .textContent(),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1714 'Where should I begin?',
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1715 );
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1716 await page.waitForFunction(() =>
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1717 document.querySelector('mjj-jrpg-character')?.getAttribute('state') ===
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1718 'default' &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1719 document.querySelectorAll('.jrpg-message[data-speaker="Epi"]').length > 1
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1720 );
261
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1721 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1722 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
1723 .textContent(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1724 'hello traveler',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1725 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1726 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1727 await page.locator(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1728 '.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
1729 ).count(),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1730 0,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1731 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1732 assert.deepEqual(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1733 await page.evaluate(() => {
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1734 const event = window.__jrpgStreamEvents.find(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1735 item => item.type === 'tool.started',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1736 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1737 return {
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1738 name: event?.data.tool?.name,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1739 type: event?.type,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1740 };
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1741 }),
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1742 {
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1743 name: 'mock-search',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1744 type: 'tool.started',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1745 },
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1746 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1747 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1748 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
1749 'TURN 1 / 1',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1750 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1751 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1752 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
1753 true,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1754 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1755 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1756 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
1757 true,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1758 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1759 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
1760 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1761 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
1762 'START',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1763 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1764 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1765 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
1766 0,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1767 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1768 assert.equal(
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1769 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
1770 1,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1771 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1772 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
1773 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1774 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
1775 'TURN 1 / 1',
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1776 );
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1777 assert.equal(
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1778 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
1779 1,
b401627fc49e Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 260
diff changeset
1780 );
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1781 assert.equal(await page.locator('#jrpg-message').isEnabled(), true);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1782
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1783 await page.waitForFunction(() => navigator.serviceWorker?.controller);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1784 await page.reload({ waitUntil: 'networkidle' });
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1785 await page.evaluate(() => document.fonts.ready);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1786 const controlledReload = await page.evaluate(() => {
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1787 const shell = document.querySelector('.jrpg-shell').getBoundingClientRect();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1788 return {
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1789 art: getComputedStyle(document.querySelector('.jrpg-workspace'))
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1790 .backgroundImage,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1791 fillsViewport: shell.left === 0 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1792 shell.top === 0 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1793 Math.abs(shell.right - innerWidth) < 1 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1794 Math.abs(shell.bottom - innerHeight) < 1,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1795 fontLoaded: document.fonts.check('16px "Pixel Mplus"'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1796 fontFamily: getComputedStyle(
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1797 document.querySelector('.jrpg-brand h1'),
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1798 ).fontFamily,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1799 theme: document.documentElement.dataset.zenTheme,
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1800 };
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1801 });
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
1802 assert.match(controlledReload.art, /background-frame-2\.webp/);
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1803 assert.equal(controlledReload.fillsViewport, true);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1804 assert.equal(controlledReload.fontLoaded, true);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1805 assert.equal(controlledReload.fontFamily, '"Pixel Mplus"');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1806 assert.equal(controlledReload.theme, 'cyberpunk');
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1807 assert.deepEqual(errors, []);
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1808 await context.close();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1809
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1810 const mobileContext = await browser.newContext({
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1811 colorScheme: 'light',
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1812 viewport: { width: 360, height: 640 },
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1813 });
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1814 const mobilePage = await mobileContext.newPage();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1815 await mobilePage.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1816 await mobilePage.waitForFunction(() =>
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1817 customElements.get('mjj-composer') &&
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1818 customElements.get('mjj-jrpg-menu')
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1819 );
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1820 const mobile = await mobilePage.evaluate(() => {
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1821 const workspace = document.querySelector('.jrpg-workspace')
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1822 .getBoundingClientRect();
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1823 const scene = document.querySelector('.jrpg-scene').getBoundingClientRect();
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1824 const utility = document.querySelector('.jrpg-utility').getBoundingClientRect();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1825 const composer = document.querySelector('mjj-composer')
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1826 .getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1827 const brand = document.querySelector('.jrpg-brand').getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1828 const brandLink = document.querySelector('.jrpg-brand a').getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1829 const turnNavigation = document.querySelector('.jrpg-turn-navigation');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1830 const previousTurn = turnNavigation.querySelector('[data-turn-previous]')
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1831 .getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1832 const turnPosition = turnNavigation.querySelector('[data-turn-position]')
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1833 .getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1834 const nextTurn = turnNavigation.querySelector('[data-turn-next]')
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1835 .getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1836 const composerForm = document.querySelector('.jrpg-composer')
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1837 .getBoundingClientRect();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1838 const composerTextarea = document.querySelector('#jrpg-message')
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1839 .getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1840 const sendButton = document.querySelector(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1841 '.jrpg-composer button[type="submit"]',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1842 ).getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1843 const sendOwner = document.querySelector(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1844 '.jrpg-composer zen-button:has(button[type="submit"])',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1845 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1846 const composerField = document.querySelector(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1847 '.jrpg-composer [data-composer-control] > zen-field',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1848 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1849 const composerLabel = composerField.querySelector('label');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1850 const sendLabel = document.querySelector('[data-composer-action-label]');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1851 const menuElement = document.querySelector('mjj-jrpg-menu');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1852 const menu = menuElement.getBoundingClientRect();
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1853 const shell = document.querySelector('.jrpg-shell').getBoundingClientRect();
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1854 const hamburger = document.querySelector('[data-mobile-menu-toggle]');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1855 const hamburgerBox = hamburger?.getBoundingClientRect();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1856 const dialog = document.querySelector('[data-mobile-destination-dialog]');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1857 const destinationContent = document.querySelector(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1858 '[data-mobile-destination-content]',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1859 );
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1860 const closeTo = (value, expected, tol = 0.025) =>
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1861 Math.abs(value - expected) < tol;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1862 const wsW = workspace.width;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1863 const wsH = workspace.height;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1864 const mobileArt = getComputedStyle(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1865 document.querySelector('.jrpg-workspace'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1866 ).backgroundImage;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1867 const mobileArtIsCorrect = mobileArt.includes('background-frame-mobile.webp');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1868 const aperturesTolerance = [
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1869 closeTo((scene.left - workspace.left) / wsW, 0.048),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1870 closeTo((scene.top - workspace.top) / wsH, 0.073),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1871 closeTo(scene.width / wsW, 0.904),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1872 closeTo(scene.height / wsH, 0.712),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1873 closeTo((composer.left - workspace.left) / wsW, 0.048),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1874 closeTo((composer.top - workspace.top) / wsH, 0.796),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1875 closeTo(composer.width / wsW, 0.904),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1876 closeTo(composer.height / wsH, 0.177),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1877 closeTo((hamburgerBox.left - workspace.left) / wsW, 0.872),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1878 closeTo((hamburgerBox.top - workspace.top) / wsH, 0.013),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1879 closeTo(hamburgerBox.width / wsW, 0.094),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1880 closeTo(hamburgerBox.height / wsH, 0.053),
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1881 ].every(Boolean);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1882 const hamburgerPresent = hamburger !== null &&
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1883 hamburger.getAttribute('aria-expanded') === 'false' &&
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1884 hamburgerBox !== null &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1885 hamburgerBox.width > 0 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1886 hamburgerBox.height > 0;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1887 const composerVisible = composer.width > 0 && composer.height > 0;
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1888 return {
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1889 aperturesTolerance,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1890 brandAligned:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1891 closeTo((brand.top - workspace.top) / wsH, 0.013) &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1892 closeTo(brand.height / wsH, 0.053) &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1893 Math.abs(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1894 brandLink.left + brandLink.width / 2 -
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1895 (workspace.left + workspace.width / 2)
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1896 ) < 2,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1897 brandVisible:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1898 getComputedStyle(document.querySelector('.jrpg-brand')).display ===
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1899 'grid' &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1900 document.querySelector('.jrpg-brand').textContent.includes('MrJuneJune'),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1901 composerContentAligned:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1902 composerForm.left >= composer.left &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1903 composerForm.top >= composer.top &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1904 composer.right - composerForm.right <= 8 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1905 composer.bottom - composerForm.bottom <= 8 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1906 composerForm.left - composer.left <= 8 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1907 composerForm.top - composer.top <= 8 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1908 sendButton.bottom < composerTextarea.bottom &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1909 composerTextarea.bottom - sendButton.bottom <= 16,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1910 composerGeometry: {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1911 composer: {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1912 bottom: composer.bottom,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1913 left: composer.left,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1914 right: composer.right,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1915 top: composer.top,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1916 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1917 form: {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1918 bottom: composerForm.bottom,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1919 left: composerForm.left,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1920 right: composerForm.right,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1921 top: composerForm.top,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1922 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1923 send: {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1924 bottom: sendButton.bottom,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1925 left: sendButton.left,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1926 right: sendButton.right,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1927 top: sendButton.top,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1928 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1929 textarea: {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1930 bottom: composerTextarea.bottom,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1931 left: composerTextarea.left,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1932 right: composerTextarea.right,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1933 top: composerTextarea.top,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1934 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1935 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1936 composerFieldUsesSpace:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1937 composerTextarea.left === composerForm.left &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1938 composerTextarea.right === composerForm.right &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1939 sendButton.left > composerTextarea.left &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1940 sendButton.right < composerTextarea.right &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1941 sendButton.top > composerTextarea.top &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1942 sendButton.bottom < composerTextarea.bottom,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1943 composerLabelHidden:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1944 composerLabel.getBoundingClientRect().width <= 1 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1945 composerLabel.getBoundingClientRect().height <= 1,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1946 composerVisible,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1947 dialogClosed: !dialog.open,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1948 fillsViewport: shell.left === 0 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1949 shell.top === 0 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1950 Math.abs(shell.right - innerWidth) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1951 Math.abs(shell.bottom - innerHeight) < 1,
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1952 fillsWidth: shell.left === 0 &&
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1953 Math.abs(shell.right - innerWidth) < 1,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1954 hamburgerPresent,
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1955 initialScroll: scrollY,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1956 mediaMatches: matchMedia(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1957 '(max-width: 52rem) and (orientation: portrait)',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1958 ).matches,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1959 menuInModal: menuElement.parentElement === destinationContent,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1960 menuHidden: menu.width === 0 && menu.height === 0,
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1961 modalOwner: destinationContent.closest('mjj-window-modal')?.localName,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
1962 mobileArtIsCorrect,
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
1963 noOverflow: document.documentElement.scrollWidth <= innerWidth,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1964 sendButtonCompact:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1965 Math.abs(sendButton.width - sendButton.height) < 1 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1966 sendButton.width <= 44 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1967 getComputedStyle(sendLabel).display === 'none',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1968 telemetryHidden: getComputedStyle(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1969 document.querySelector('.jrpg-frame-telemetry'),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1970 ).display === 'none',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1971 turnNavigationAligned:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1972 Math.abs(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1973 turnPosition.left + turnPosition.width / 2 -
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1974 (workspace.left + workspace.width / 2)
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1975 ) < 2 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1976 Math.abs(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1977 previousTurn.top + previousTurn.height / 2 -
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1978 (nextTurn.top + nextTurn.height / 2)
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1979 ) < 1 &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1980 previousTurn.left < turnPosition.left &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1981 nextTurn.right > turnPosition.right,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1982 turnNavigationGeometry: {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1983 nextCenter: nextTurn.left + nextTurn.width / 2,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1984 positionCenter: turnPosition.left + turnPosition.width / 2,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1985 previousCenter: previousTurn.left + previousTurn.width / 2,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1986 workspaceCenter: workspace.left + workspace.width / 2,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1987 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1988 topLeftClear: document.elementFromPoint(10, 10)?.classList
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1989 .contains('jrpg-workspace'),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1990 utilityHidden: utility.width === 0 && utility.height === 0,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1991 utilityInModal: document.querySelector('.jrpg-utility').parentElement ===
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1992 destinationContent,
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1993 usesCyberScroll:
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1994 destinationContent.localName === 'zen-scroll-area' &&
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1995 destinationContent.hasAttribute('data-cyber-scroll') &&
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1996 getComputedStyle(destinationContent).scrollbarColor !== 'auto',
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1997 usesDesignSystemControls:
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1998 !composerField.hasAttribute('appearance') &&
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
1999 !sendOwner.hasAttribute('appearance'),
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2000 workspaceFills: Math.abs(workspace.left) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2001 Math.abs(workspace.top) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2002 Math.abs(workspace.right - innerWidth) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2003 Math.abs(workspace.bottom - innerHeight) < 1,
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
2004 };
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
2005 });
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2006 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
2007 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
2008 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
2009 assert.equal(
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2010 mobile.composerContentAligned,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2011 true,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2012 `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
2013 );
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2014 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
2015 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
2016 assert.equal(mobile.composerVisible, true, 'composer visible');
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2017 assert.equal(mobile.dialogClosed, true, 'destination modal starts closed');
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2018 assert.equal(mobile.fillsViewport, true, 'shell fills viewport');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2019 assert.equal(mobile.fillsWidth, true, 'shell fills width');
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2020 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
2021 assert.equal(mobile.initialScroll, 0, 'no initial scroll');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2022 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
2023 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
2024 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2025 mobile.menuInModal,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2026 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2027 `menu is hosted by the mobile modal: ${JSON.stringify(mobile)}`,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2028 );
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2029 assert.equal(mobile.noOverflow, true, 'no horizontal overflow at 360x640');
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2030 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
2031 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
2032 assert.equal(
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2033 mobile.turnNavigationAligned,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2034 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2035 `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
2036 );
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2037 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
2038 assert.equal(mobile.utilityInModal, true, 'destination view is hosted by the mobile modal');
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
2039 assert.equal(mobile.modalOwner, 'mjj-window-modal');
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
2040 assert.equal(mobile.usesCyberScroll, true, 'JRPG modal uses the shared cyber scroll area');
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2041 assert.equal(mobile.usesDesignSystemControls, true, 'composer uses styled Zenbu controls');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2042 assert.equal(mobile.workspaceFills, true, 'workspace fills full viewport');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2043 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
2044
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2045 // The top-right trigger opens the modal menu.
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2046 await mobilePage.locator('[data-mobile-menu-toggle]').click();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2047 await mobilePage.locator('[data-mobile-destination-dialog]').waitFor({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2048 state: 'visible',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2049 });
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
2050 await mobilePage.locator('[data-mobile-destination-dialog]').evaluate(dialog =>
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
2051 Promise.all(dialog.getAnimations().map(animation => animation.finished))
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
2052 );
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2053 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2054 await mobilePage.locator('[data-mobile-menu-toggle]')
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2055 .getAttribute('aria-expanded'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2056 'true',
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2057 'menu trigger reflects the open modal',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2058 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2059 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2060 await mobilePage.locator('mjj-jrpg-menu').isVisible(),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2061 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2062 'destination menu is visible inside the modal',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2063 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2064
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2065 // Every destination replaces the menu inside the same modal.
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2066 await mobilePage.locator('button[data-preview="conversations"]').click();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2067 await mobilePage.locator('mjj-conversation-archive').waitFor({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2068 state: 'visible',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2069 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2070 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2071 await mobilePage.locator('[data-mobile-destination-title]').textContent(),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2072 'Conversations',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2073 'conversation archive is a named modal destination',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2074 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2075 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2076 await mobilePage.locator('[data-mobile-destination-dialog]').isVisible(),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2077 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2078 'conversation archive remains in the modal',
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2079 );
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2080 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2081 await mobilePage.locator('.jrpg-mobile-destination-header').evaluate(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2082 header => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2083 const items = [...header.children].filter(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2084 item => getComputedStyle(item).display !== 'none',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2085 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2086 const centers = items.map(item => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2087 const rect = item.getBoundingClientRect();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2088 return rect.top + rect.height / 2;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2089 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2090 return Math.max(...centers) - Math.min(...centers) < 2;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2091 },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2092 ),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2093 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2094 'mobile modal header controls share one row',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2095 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2096
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2097 await mobilePage.locator('[data-mobile-destination-back]').click();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2098 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2099 await mobilePage.locator('mjj-jrpg-menu').isVisible(),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2100 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2101 'modal back action returns to destinations',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2102 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2103 await mobilePage.locator('button[data-preview="resume"]').click();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2104 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2105 await mobilePage.locator('[data-preview-content]').isVisible(),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2106 true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2107 'resume view renders in the mobile modal',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2108 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2109 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2110 await mobilePage.locator('[data-mobile-destination-title]').textContent(),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2111 'Resume',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2112 'modal title follows the selected destination',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2113 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2114 await mobilePage.getByRole('button', {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2115 name: 'Close destination menu',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2116 }).click();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2117 await mobilePage.locator('[data-mobile-destination-dialog]').waitFor({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2118 state: 'hidden',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2119 });
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2120 assert.ok(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2121 await mobilePage.locator('[data-mobile-menu-toggle]').evaluate(el =>
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2122 el.tabIndex >= 0
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2123 ),
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2124 'mobile menu trigger remains keyboard accessible',
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2125 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2126 await mobileContext.close();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2127
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2128 // Test at 390x844
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2129 const mobile390Context = await browser.newContext({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2130 colorScheme: 'light',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2131 viewport: { width: 390, height: 844 },
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
2132 });
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2133 const mobile390Page = await mobile390Context.newPage();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2134 await mobile390Page.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2135 const mobile390 = await mobile390Page.evaluate(() => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2136 const workspace = document.querySelector('.jrpg-workspace')
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2137 .getBoundingClientRect();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2138 const shell = document.querySelector('.jrpg-shell').getBoundingClientRect();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2139 const mobileArt = getComputedStyle(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2140 document.querySelector('.jrpg-workspace'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2141 ).backgroundImage;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2142 return {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2143 fillsViewport: shell.left === 0 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2144 shell.top === 0 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2145 Math.abs(shell.right - innerWidth) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2146 Math.abs(shell.bottom - innerHeight) < 1,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2147 mobileArtIsCorrect: mobileArt.includes('background-frame-mobile.webp'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2148 noOverflow: document.documentElement.scrollWidth <= innerWidth,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2149 workspaceFills: Math.abs(workspace.left) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2150 Math.abs(workspace.top) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2151 Math.abs(workspace.right - innerWidth) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2152 Math.abs(workspace.bottom - innerHeight) < 1,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2153 };
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2154 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2155 assert.equal(mobile390.fillsViewport, true, 'fills viewport at 390x844');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2156 assert.equal(mobile390.mobileArtIsCorrect, true, 'mobile art at 390x844');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2157 assert.equal(mobile390.noOverflow, true, 'no overflow at 390x844');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2158 assert.equal(mobile390.workspaceFills, true, 'workspace fills at 390x844');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2159 await mobile390Context.close();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2160
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2161 // Test at 320x568 (narrow)
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2162 const mobile320Context = await browser.newContext({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2163 colorScheme: 'light',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2164 viewport: { width: 320, height: 568 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2165 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2166 const mobile320Page = await mobile320Context.newPage();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2167 await mobile320Page.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2168 const mobile320 = await mobile320Page.evaluate(() => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2169 const workspace = document.querySelector('.jrpg-workspace')
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2170 .getBoundingClientRect();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2171 const shell = document.querySelector('.jrpg-shell').getBoundingClientRect();
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2172 const composer = document.querySelector('mjj-composer')
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2173 .getBoundingClientRect();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2174 const menu = document.querySelector('mjj-jrpg-menu').getBoundingClientRect();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2175 const mobileArt = getComputedStyle(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2176 document.querySelector('.jrpg-workspace'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2177 ).backgroundImage;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2178 return {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2179 composerPresent: composer.width > 0 && composer.height > 0,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2180 fillsViewport: shell.left === 0 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2181 shell.top === 0 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2182 Math.abs(shell.right - innerWidth) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2183 Math.abs(shell.bottom - innerHeight) < 1,
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2184 menuHidden: menu.width === 0 && menu.height === 0,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2185 mobileArtIsCorrect: mobileArt.includes('background-frame-mobile.webp'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2186 noOverflow: document.documentElement.scrollWidth <= innerWidth,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2187 workspaceFills: Math.abs(workspace.left) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2188 Math.abs(workspace.top) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2189 Math.abs(workspace.right - innerWidth) < 1 &&
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2190 Math.abs(workspace.bottom - innerHeight) < 1,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2191 };
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2192 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2193 assert.equal(mobile320.composerPresent, true, 'composer present at 320x568');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2194 assert.equal(mobile320.fillsViewport, true, 'fills viewport at 320x568');
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2195 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
2196 assert.equal(mobile320.mobileArtIsCorrect, true, 'mobile art at 320x568');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2197 assert.equal(mobile320.noOverflow, true, 'no overflow at 320x568');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2198 assert.equal(mobile320.workspaceFills, true, 'workspace fills at 320x568');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2199 await mobile320Context.close();
263
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2200
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2201 const shortContext = await browser.newContext({
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2202 colorScheme: 'dark',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2203 viewport: { width: 900, height: 500 },
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2204 });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2205 const shortPage = await shortContext.newPage();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2206 await shortPage.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2207 const shortLayout = await shortPage.evaluate(() => {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2208 const scene = document.querySelector('.jrpg-scene').getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2209 const character = document.querySelector('mjj-jrpg-character')
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2210 .getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2211 const chat = document.querySelector('mjj-jrpg-chat')
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2212 .getBoundingClientRect();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2213 return {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2214 characterInside: character.left >= scene.left &&
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2215 character.right <= scene.right,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2216 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
2217 noSceneOverflow: document.querySelector('.jrpg-scene').scrollWidth <=
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2218 document.querySelector('.jrpg-scene').clientWidth,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2219 };
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2220 });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2221 assert.deepEqual(shortLayout, {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2222 characterInside: true,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2223 chatInside: true,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2224 noSceneOverflow: true,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2225 });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2226 await shortContext.close();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2227
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2228 const forcedColorsContext = await browser.newContext({
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2229 forcedColors: 'active',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2230 viewport: { width: 1280, height: 900 },
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2231 });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2232 const forcedColorsPage = await forcedColorsContext.newPage();
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2233 await forcedColorsPage.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2234 assert.deepEqual(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2235 await forcedColorsPage.evaluate(() => ({
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2236 sceneBar: getComputedStyle(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2237 document.querySelector('.jrpg-scene'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2238 '::before',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2239 ).backgroundImage,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2240 workspace: getComputedStyle(
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2241 document.querySelector('.jrpg-workspace'),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2242 ).backgroundImage,
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2243 })),
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2244 {
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2245 sceneBar: 'none',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2246 workspace: 'none',
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2247 },
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2248 );
ee04e4e69fed Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 262
diff changeset
2249 await forcedColorsContext.close();
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
2250 }
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
2251
242
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2252 async function testHlsPlayer(browser, siteRoot) {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2253 const page = await browser.newPage();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2254 const errors = [];
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2255 const mediaRequests = [];
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2256 let testingExpectedFailure = false;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2257 let testingExpectedReload = false;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2258 page.on('pageerror', error => errors.push(`pageerror: ${error.message}`));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2259 page.on('console', message => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2260 if (message.type() !== 'error') return;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2261 if (testingExpectedFailure &&
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2262 message.text().startsWith('Failed to load resource:')) return;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2263 errors.push(`console: ${message.text()}`);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2264 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2265 page.on('requestfailed', request => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2266 if (testingExpectedReload &&
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2267 request.failure()?.errorText === 'net::ERR_ABORTED') return;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2268 errors.push(`requestfailed: ${request.url()} ${request.failure()?.errorText || ''}`);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2269 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2270 page.on('request', request => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2271 if (/\.(?:m3u8|m4s|mp4)(?:\?|$)/.test(request.url())) {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2272 mediaRequests.push(request.url());
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2273 }
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2274 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2275
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2276 const playlistResponse = await fetch(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2277 `${baseUrl}/public/hls-sample/master.m3u8`,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2278 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2279 assert.equal(playlistResponse.status, 200);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2280 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2281 playlistResponse.headers.get('content-type') || '',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2282 /^application\/vnd\.apple\.mpegurl/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2283 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2284 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2285 await playlistResponse.text(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2286 /#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
2287 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2288
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2289 const variantResponse = await fetch(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2290 `${baseUrl}/public/hls-sample/vp9-stream.m3u8`,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2291 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2292 assert.equal(variantResponse.status, 200);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2293 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2294 await variantResponse.text(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2295 /#EXT-X-MAP:URI="vp9-init\.mp4"/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2296 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2297
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2298 const segmentResponse = await fetch(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2299 `${baseUrl}/public/hls-sample/vp9-segment000.m4s`,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2300 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2301 assert.equal(segmentResponse.status, 200);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2302 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2303 segmentResponse.headers.get('content-type') || '',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2304 /^video\/iso\.segment/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2305 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2306 const transportStreamResponse = await fetch(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2307 `${baseUrl}/public/hls-sample/h264-ts-segment000.ts`,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2308 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2309 assert.equal(transportStreamResponse.status, 200);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2310 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2311 transportStreamResponse.headers.get('content-type') || '',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2312 /^video\/mp2t/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2313 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2314 assert.ok((await transportStreamResponse.arrayBuffer()).byteLength > 0);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2315
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2316 await page.goto(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2317 `${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
2318 {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2319 waitUntil: 'networkidle',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2320 },
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2321 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2322 await page.getByRole('button', { name: 'Sample', exact: true }).waitFor();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2323 assert.equal(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2324 await page.locator('#hlsUrl').evaluate(input => input.defaultValue),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2325 '/public/hls-sample/h264-ts-stream.m3u8',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2326 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2327 await page.waitForFunction(() => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2328 const status = document.querySelector('#hlsStatus');
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2329 return status?.dataset.state === 'ready' ||
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2330 status?.dataset.state === 'error';
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2331 }, null, { timeout: 15000 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2332 const terminalState = await page.locator('#hlsStatus').getAttribute('data-state');
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2333 if (terminalState !== 'ready') {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2334 throw new Error(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2335 `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
2336 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2337 }
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2338 assert.match(await page.locator('#hlsStatus').textContent(), /Stream ready/);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2339 assert.equal(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2340 await page.locator('[data-detail="mode"]').textContent(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2341 'hls.js',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2342 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2343 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2344 await page.locator('[data-detail="segments"]').textContent(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2345 /Managed by hls\.js|adaptive levels/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2346 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2347 await page.waitForFunction(() => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2348 const video = document.querySelector('#hlsVideo');
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2349 return video.readyState >= HTMLMediaElement.HAVE_METADATA &&
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2350 Number.isFinite(video.duration) &&
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2351 video.duration >= 14;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2352 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2353 const firstFrame = await page.locator('#hlsVideo').evaluate(video => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2354 const canvas = document.createElement('canvas');
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2355 canvas.width = video.videoWidth;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2356 canvas.height = video.videoHeight;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2357 const context = canvas.getContext('2d');
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2358 context.drawImage(video, 0, 0);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2359 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
2360 let total = 0;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2361 for (let index = 0; index < pixels.length; index += 4) {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2362 total += pixels[index] + pixels[index + 1] + pixels[index + 2];
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2363 }
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2364 return total / (canvas.width * canvas.height * 3);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2365 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2366 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
2367 await page.locator('#hlsVideo').evaluate(video => video.play());
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2368 await page.waitForFunction(() => document.querySelector('#hlsVideo').currentTime > 0.2);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2369 await page.locator('#hlsVideo').evaluate(video => video.pause());
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2370 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
2371 assert.ok(mediaRequests.some(url => url.endsWith('-stream.m3u8')));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2372 assert.ok(mediaRequests.some(url => url.endsWith('-init.mp4')));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2373 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
2374
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2375 await page.evaluate(() => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2376 window.hlsPlayer.hls.trigger(window.Hls.Events.ERROR, {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2377 fatal: true,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2378 type: window.Hls.ErrorTypes.MEDIA_ERROR,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2379 details: 'testRuntimeFailure',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2380 error: new Error('runtime segment failed'),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2381 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2382 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2383 await page.locator('#hlsStatus[data-state="error"]').waitFor();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2384 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2385 await page.locator('#hlsStatus').textContent(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2386 /runtime segment failed/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2387 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2388 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
2389 await page.getByRole('button', { name: 'Load', exact: true }).click();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2390 await page.locator('#hlsStatus[data-state="ready"]').waitFor();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2391
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2392 let delayedSegment = true;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2393 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
2394 if (delayedSegment) {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2395 delayedSegment = false;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2396 await new Promise(resolve => setTimeout(resolve, 250));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2397 }
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2398 await route.continue();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2399 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2400 testingExpectedReload = true;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2401 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
2402 await page.getByRole('button', { name: 'Load', exact: true }).click();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2403 await page.waitForTimeout(25);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2404 await page.getByRole('button', { name: 'Load', exact: true }).click();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2405 await page.locator('#hlsStatus[data-state="ready"]').waitFor();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2406 testingExpectedReload = false;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2407 assert.match(await page.locator('#hlsStatus').textContent(), /Stream ready/);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2408
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2409 await page.evaluate(() => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2410 window.__hlsObjectUrls = { created: [], revoked: [] };
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2411 const createObjectURL = URL.createObjectURL.bind(URL);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2412 const revokeObjectURL = URL.revokeObjectURL.bind(URL);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2413 URL.createObjectURL = value => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2414 const url = createObjectURL(value);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2415 window.__hlsObjectUrls.created.push(url);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2416 return url;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2417 };
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2418 URL.revokeObjectURL = url => {
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2419 window.__hlsObjectUrls.revoked.push(url);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2420 revokeObjectURL(url);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2421 };
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2422 });
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2423 const localFiles = listFiles(path.join(siteRoot, 'public/hls-sample'));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2424 await page.locator('#hlsFiles').setInputFiles(localFiles);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2425 await page.waitForFunction(() =>
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2426 document.querySelector('#hlsUrl')?.value.startsWith('Local: ')
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2427 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2428 await page.locator('#hlsStatus[data-state="ready"]').waitFor();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2429 assert.match(await page.locator('#hlsUrl').inputValue(), /^Local: /);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2430 assert.equal(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2431 await page.locator('[data-detail="mode"]').textContent(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2432 'hls.js',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2433 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2434 await page.locator('#hlsVideo').evaluate(video => video.play());
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2435 await page.waitForFunction(() => document.querySelector('#hlsVideo').currentTime > 0.3);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2436 await page.locator('#hlsVideo').evaluate(video => video.pause());
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2437 const incompleteLocalFiles = localFiles.filter(file =>
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2438 file.endsWith('master.m3u8') ||
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2439 file.endsWith('vp9-stream.m3u8')
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2440 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2441 await page.locator('#hlsFiles').setInputFiles(incompleteLocalFiles);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2442 await page.locator('#hlsStatus[data-state="error"]').waitFor();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2443 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2444 await page.locator('#hlsStatus').textContent(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2445 /Local HLS file is missing/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2446 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2447 const objectUrlCounts = await page.evaluate(() => ({
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2448 created: window.__hlsObjectUrls.created.length,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2449 revoked: window.__hlsObjectUrls.revoked.length,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2450 }));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2451 assert.ok(objectUrlCounts.created > 10, JSON.stringify(objectUrlCounts));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2452 assert.ok(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2453 objectUrlCounts.revoked >= objectUrlCounts.created,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2454 JSON.stringify(objectUrlCounts),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2455 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2456
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2457 await page.route('**/invalid.m3u8', route => route.fulfill({
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2458 status: 404,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2459 body: 'not found',
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2460 }));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2461 testingExpectedFailure = true;
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2462 await page.locator('#hlsUrl').fill(`${baseUrl}/invalid.m3u8`);
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2463 await page.getByRole('button', { name: 'Load', exact: true }).click();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2464 await page.locator('#hlsStatus[data-state="error"]').waitFor();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2465 assert.match(
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2466 await page.locator('#hlsStatus').textContent(),
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2467 /404|manifestLoadError|Playlist request failed/,
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2468 );
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2469
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2470 if (errors.length) throw new Error(errors.join('\n'));
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2471 await page.close();
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2472 }
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
2473
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2474 function findFreePort() {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2475 return new Promise((resolve, reject) => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2476 const socket = net.createServer();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2477 socket.once('error', reject);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2478 socket.listen(0, '127.0.0.1', () => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2479 const address = socket.address();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2480 socket.close(error => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2481 if (error) reject(error);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2482 else resolve(String(address.port));
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2483 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2484 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2485 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2486 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2487
264
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 /* Conversation URL routing regression tests (Fixes 1–4) */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2490 /* ------------------------------------------------------------------ */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2491
265
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2492 async function testRoleGreetings(browser) {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2493 const cases = [
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2494 {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2495 name: 'guest',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2496 session: {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2497 kind: 'guest',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2498 csrfToken: 'guest-greeting-csrf',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2499 quota: null,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2500 },
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2501 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
2502 },
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2503 {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2504 name: 'invited',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2505 session: {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2506 kind: 'user',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2507 username: 'friend',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2508 role: 'member',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2509 mustChangePassword: false,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2510 csrfToken: 'friend-greeting-csrf',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2511 quota: null,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2512 },
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2513 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
2514 },
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2515 {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2516 name: 'admin',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2517 session: {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2518 kind: 'user',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2519 username: 'june',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2520 role: 'admin',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2521 mustChangePassword: false,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2522 csrfToken: 'admin-greeting-csrf',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2523 quota: null,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2524 },
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2525 expected: 'Hi June! I’m Epi-chan.',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2526 },
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2527 ];
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2528
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2529 for (const testCase of cases) {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2530 const context = await browser.newContext({ serviceWorkers: 'block' });
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2531 const page = await context.newPage();
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2532 await page.route('**/api/auth/session', route => route.fulfill({
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2533 status: 200,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2534 contentType: 'application/json',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2535 body: JSON.stringify(testCase.session),
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2536 }));
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2537 await page.route('**/api/conversations**', route => route.fulfill({
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2538 status: 200,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2539 contentType: 'application/json',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2540 body: JSON.stringify({ conversations: [], cursor: null }),
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2541 }));
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2542 await page.goto(`${baseUrl}/jrpg`, { waitUntil: 'domcontentloaded' });
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2543 const greeting = page.locator('[data-greeting]');
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2544 await greeting.waitFor({ state: 'visible' });
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2545 if (testCase.name === 'guest') {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2546 await page.locator('[data-greeting][data-streaming="true"]').waitFor({
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2547 state: 'visible',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2548 });
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2549 }
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2550 await page.waitForFunction(() => {
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2551 const item = document.querySelector('[data-greeting]');
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2552 return item && !item.hasAttribute('data-streaming');
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2553 });
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2554 assert.match(
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2555 await greeting.locator('p').textContent(),
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2556 new RegExp(testCase.expected.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')),
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2557 `${testCase.name} receives its role-specific Epi greeting`,
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2558 );
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2559 await context.close();
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2560 }
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2561 }
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2562
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2563 async function testConversationRouting(browser) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2564 const CONV_A = 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa';
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2565 const CONV_B = 'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb';
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2566 const GUEST_SESSION = {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2567 kind: 'guest', csrfToken: 'test-csrf',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2568 quota: {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2569 turnsLimit: 10, turnsUsed: 0, turnsRemaining: 10,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2570 outputTokensLimit: 10000, outputTokensUsed: 0,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2571 outputTokensReserved: 0, outputTokensRemaining: 10000,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2572 resetsAt: Math.floor(Date.now() / 1000) + 86400,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2573 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2574 };
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2575
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2576 /* 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
2577 {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2578 const context = await browser.newContext({ serviceWorkers: 'block' });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2579 await context.addInitScript(id => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2580 sessionStorage.setItem('mjj-jrpg-conversation-id', id);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2581 }, CONV_A);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2582 const page = await context.newPage();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2583 let detailRequestCount = 0;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2584 await page.route('**/api/auth/session', route => route.fulfill({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2585 status: 200, contentType: 'application/json',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2586 body: JSON.stringify(GUEST_SESSION),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2587 }));
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2588 await page.route('**/api/conversations**', route => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2589 const url = new URL(route.request().url());
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2590 if (url.pathname === '/api/conversations') {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2591 return route.fulfill({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2592 status: 200, contentType: 'application/json',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2593 body: JSON.stringify({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2594 conversations: [{
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2595 id: CONV_A,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2596 title: 'Earlier quest',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2597 turn_count: 2,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2598 }],
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2599 cursor: null,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2600 }),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2601 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2602 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2603 return route.fulfill({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2604 status: 404, contentType: 'application/json',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2605 body: JSON.stringify({ error: { message: 'Not found' } }),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2606 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2607 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2608 await page.route(`**/api/conversations/${CONV_A}`, route => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2609 detailRequestCount += 1;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2610 return route.fulfill({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2611 status: 200, contentType: 'application/json',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2612 body: JSON.stringify({
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2613 id: CONV_A,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2614 title: 'Earlier quest',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2615 turns: [{ role: 'assistant', content: 'Welcome back.' }],
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2616 }),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2617 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2618 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2619
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2620 await page.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2621 assert.equal(detailRequestCount, 0, 'latest conversation is not opened automatically');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2622 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2623 new URL(page.url()).searchParams.has('conversation'),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2624 false,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2625 'returning visit remains a fresh conversation URL',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2626 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2627 await page.waitForFunction(() => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2628 const greeting = document.querySelector('[data-greeting] p');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2629 return greeting?.textContent.includes('Open Conversations');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2630 });
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2631 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2632 await page.evaluate(() =>
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2633 sessionStorage.getItem('mjj-jrpg-conversation-id')),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2634 null,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2635 'stale active conversation state is cleared',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2636 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2637
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2638 await page.locator('button[data-preview="conversations"]').click();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2639 const selectedConversation = page.waitForResponse(response =>
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2640 new URL(response.url()).pathname === `/api/conversations/${CONV_A}`);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2641 await page.locator('[data-conv-open]').click();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2642 assert.equal((await selectedConversation).status(), 200);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2643 assert.ok(detailRequestCount >= 1, 'conversation opens after explicit selection');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2644 await page.waitForFunction(id =>
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2645 new URL(window.location.href).searchParams.get('conversation') === id,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2646 CONV_A);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2647 assert.equal(
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2648 new URL(page.url()).searchParams.get('conversation'),
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2649 CONV_A,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2650 'explicit selection writes the conversation URL',
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2651 );
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2652 await context.close();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2653 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2654
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2655 /* ---- 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
2656 {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2657 const storedId = 'cccccccc-cccc-4ccc-8ccc-cccccccccccc';
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2658 const context = await browser.newContext({ serviceWorkers: 'block' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2659 await context.addInitScript(id => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2660 sessionStorage.setItem('mjj-jrpg-conversation-id', id);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2661 }, storedId);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2662 const page = await context.newPage();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2663 const storedIdFetched = [];
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2664 await page.route('**/api/auth/session', route => route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2665 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2666 body: JSON.stringify(GUEST_SESSION),
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 await page.route('**/api/conversations**', route => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2669 const url = new URL(route.request().url());
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2670 if (url.pathname.endsWith(`/${storedId}`)) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2671 storedIdFetched.push(route.request().url());
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 if (url.pathname === '/api/conversations') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2674 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2675 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2676 body: JSON.stringify({ conversations: [], cursor: null }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2677 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2678 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2679 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2680 status: 404, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2681 body: JSON.stringify({ error: { message: 'Not found' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2682 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2683 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2684 await page.route('**/api/conversations/claim', route => route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2685 status: 503,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2686 contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2687 body: JSON.stringify({ error: { message: 'Service unavailable' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2688 }));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2689 await page.goto(`${baseUrl}/jrpg?conversation=not-a-valid-uuid`, {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2690 waitUntil: 'networkidle',
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 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2693 storedIdFetched.length, 0,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2694 'Fix 3: malformed ?conversation param must not trigger sessionStorage fallback',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2695 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2696 await context.close();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2697 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2698
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2699 /* ---- 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
2700 {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2701 const legacyStoredId = 'dddddddd-dddd-4ddd-8ddd-dddddddddddd';
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2702 const context = await browser.newContext({ serviceWorkers: 'block' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2703 /* 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
2704 await context.addInitScript(id => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2705 sessionStorage.setItem('mjj-jrpg-conversation-id', id);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2706 }, legacyStoredId);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2707 const page = await context.newPage();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2708 const pageErrors = [];
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2709 page.on('pageerror', e => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2710 if (!e.message.startsWith('Failed to load resource:')) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2711 pageErrors.push(`pageerror: ${e.message}`);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2712 }
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 await page.route('**/api/auth/session', route => route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2715 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2716 body: JSON.stringify({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2717 kind: 'user', username: 'tester', role: 'member',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2718 csrfToken: 'test-csrf', quota: null,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2719 }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2720 }));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2721 await page.route('**/api/conversations**', route => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2722 const url = new URL(route.request().url());
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2723 const req = route.request();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2724 if (url.pathname === '/api/conversations' && req.method() === 'GET') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2725 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2726 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2727 body: JSON.stringify({ conversations: [], cursor: null }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2728 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2729 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2730 if (url.pathname === `/api/conversations/${legacyStoredId}` && req.method() === 'GET') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2731 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2732 status: 404, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2733 body: JSON.stringify({ error: { message: 'Not found' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2734 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2735 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2736 if (url.pathname === '/api/conversations/claim' && req.method() === 'POST') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2737 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2738 status: 503, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2739 body: JSON.stringify({ error: { message: 'Service unavailable' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2740 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2741 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2742 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2743 status: 404, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2744 body: JSON.stringify({ error: { message: 'Not found' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2745 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2746 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2747 await page.route('**/api/conversations/claim', route => route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2748 status: 503,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2749 contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2750 body: JSON.stringify({ error: { message: 'Service unavailable' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2751 }));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2752 await page.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2753
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2754 /* Open archive panel so the legacy claim status is visible */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2755 await page.locator('button[data-preview="conversations"]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2756 await page.locator('mjj-conversation-archive').waitFor({ state: 'visible' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2757
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2758 /* Init should have called showLegacyClaim() — wait for the button */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2759 await page.waitForFunction(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2760 () => document.querySelector('[data-archive-claim]') !== null,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2761 null, { timeout: 5000 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2762 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2763
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2764 /* First claim attempt — returns 503 */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2765 const firstClaimResponse = page.waitForResponse(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2766 response => response.url().includes('/api/conversations/claim'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2767 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2768 await page.locator('[data-archive-claim]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2769 const firstClaimStatus = (await firstClaimResponse).status();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2770 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2771 firstClaimStatus,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2772 503,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2773 `claim fixture returns the mocked service failure, got ${firstClaimStatus}`,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2774 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2775
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2776 /* 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
2777 await page.waitForFunction(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2778 () => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2779 const status = document.querySelector('[data-archive-status]');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2780 return status && !status.hidden && status.textContent.includes('Claim failed');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2781 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2782 null, { timeout: 5000 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2783 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2784
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2785 /* Key must be retained in sessionStorage on 5xx */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2786 const keyAfterFail = await page.evaluate(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2787 () => sessionStorage.getItem('mjj-jrpg-legacy-claim'),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2788 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2789 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2790 keyAfterFail, legacyStoredId,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2791 '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
2792 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2793
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2794 /* Button must be present and enabled for retry */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2795 await page.locator('[data-archive-claim]').waitFor({ state: 'visible' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2796
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2797 /* 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
2798 await page.locator('[data-archive-claim]').evaluate(btn => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2799 btn.dataset.claimGen = '1';
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2800 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2801
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2802 /* 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
2803 await page.locator('[data-archive-claim]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2804
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2805 /* 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
2806 await page.waitForFunction(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2807 () => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2808 const btn = document.querySelector('[data-archive-claim]');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2809 return btn !== null && btn.dataset.claimGen !== '1';
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2810 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2811 null, { timeout: 5000 },
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2812 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2813
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2814 assert.deepEqual(pageErrors, [], 'no page errors in legacy claim test');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2815 await context.close();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2816 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2817
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2818 /* ---- Fix 1: popstate during active stream converges URL and UI ---- */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2819 {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2820 let releaseStream = () => {};
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2821 const streamGate = new Promise(resolve => { releaseStream = resolve; });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2822
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2823 const context = await browser.newContext();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2824 const page = await context.newPage();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2825 const pageErrors = [];
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2826 page.on('pageerror', e => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2827 if (!e.message.startsWith('Failed to load resource:')) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2828 pageErrors.push(`pageerror: ${e.message}`);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2829 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2830 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2831 /* 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
2832 page.on('requestfailed', request => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2833 if (request.failure()?.errorText === 'net::ERR_ABORTED') return;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2834 pageErrors.push(`requestfailed: ${request.url()} ${request.failure()?.errorText || ''}`);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2835 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2836
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2837 await page.route('**/api/auth/session', route => route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2838 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2839 body: JSON.stringify(GUEST_SESSION),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2840 }));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2841 await page.route('**/api/conversations**', async route => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2842 const url = new URL(route.request().url());
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2843 const req = route.request();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2844 if (url.pathname === '/api/conversations' && req.method() === 'GET') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2845 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2846 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2847 body: JSON.stringify({ conversations: [], cursor: null }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2848 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2849 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2850 if (url.pathname === '/api/conversations' && req.method() === 'POST') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2851 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2852 status: 201, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2853 body: JSON.stringify({ id: CONV_A }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2854 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2855 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2856 if (url.pathname.endsWith('/turns') && req.method() === 'POST') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2857 /* Hold the SSE stream until the test releases it */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2858 await streamGate;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2859 try { await route.abort(); } catch { /* request may already be aborted */ }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2860 return;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2861 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2862 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2863 status: 404, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2864 body: JSON.stringify({ error: { message: 'Not found' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2865 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2866 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2867
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2868 await page.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2869 await page.waitForFunction(
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2870 () => !document.querySelector('mjj-composer textarea')?.disabled,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2871 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2872
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2873 /* Submit — creates conversation via pushState and starts stream */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2874 await page.locator('#jrpg-message').fill('routing race test');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2875 await page.locator('#jrpg-message').press('Enter');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2876
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2877 /* Stream is now active */
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2878 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
2879
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2880 const urlDuringStream = page.url();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2881 assert.ok(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2882 urlDuringStream.includes('conversation='),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2883 `Fix 1: URL must have ?conversation during stream: ${urlDuringStream}`,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2884 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2885
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2886 /* Navigate back while stream is active — URL already changes here */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2887 await page.goBack();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2888
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2889 /* Stream abort + pending-popstate application: cancel control disappears */
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
2890 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
2891
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2892 /* URL and UI must converge to the pre-stream state */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2893 const finalUrl = page.url();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2894 assert.ok(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2895 !finalUrl.includes('conversation='),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2896 `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
2897 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2898 assert.equal(
265
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2899 await page.locator(
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2900 '.jrpg-message[data-streaming="true"]:not([data-greeting])',
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2901 ).count(),
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
2902 0,
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2903 'Fix 1: no streaming message must remain after popstate back',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2904 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2905
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2906 releaseStream(); /* clean up the held route */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2907 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
2908 await context.close();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2909 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2910
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2911 /* ---- 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
2912 {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2913 let resolveConvBFetch = () => {};
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2914 const convBFetchGate = new Promise(resolve => { resolveConvBFetch = resolve; });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2915
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2916 const context = await browser.newContext();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2917 const page = await context.newPage();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2918 const pageErrors = [];
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2919 page.on('pageerror', e => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2920 if (!e.message.startsWith('Failed to load resource:')) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2921 pageErrors.push(`pageerror: ${e.message}`);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2922 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2923 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2924
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2925 await page.route('**/api/auth/session', route => route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2926 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2927 body: JSON.stringify(GUEST_SESSION),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2928 }));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2929 await page.route('**/api/conversations**', async route => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2930 const url = new URL(route.request().url());
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2931 const req = route.request();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2932 /* Empty archive: no auto-open, no gate deadlock */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2933 if (url.pathname === '/api/conversations' && req.method() === 'GET') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2934 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2935 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2936 body: JSON.stringify({ conversations: [], cursor: null }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2937 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2938 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2939 /* 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
2940 if (url.pathname === `/api/conversations/${CONV_B}` && req.method() === 'GET') {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2941 await convBFetchGate;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2942 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2943 status: 200, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2944 body: JSON.stringify({ id: CONV_B, title: 'Conv B', turns: [] }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2945 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2946 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2947 return route.fulfill({
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2948 status: 404, contentType: 'application/json',
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2949 body: JSON.stringify({ error: { message: 'Not found' } }),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2950 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2951 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2952
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2953 /* Empty archive so init completes without auto-opening any conversation */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2954 await page.goto(`${baseUrl}/jrpg`, { waitUntil: 'networkidle' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2955
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2956 /* Open archive panel — this pushes a history entry (conversations panel) */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2957 await page.locator('button[data-preview="conversations"]').click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2958 await page.locator('mjj-conversation-archive').waitFor({ state: 'visible' });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2959
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2960 /* 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
2961 await page.evaluate(id => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2962 document.querySelector('mjj-conversation-archive')
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2963 ?.addConversation({ id, title: 'Conv B', turn_count: 0 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2964 }, CONV_B);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2965
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2966 await page.waitForFunction(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2967 id => [...document.querySelectorAll('[data-conv-item]')]
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2968 .some(item => item._convId === id),
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2969 CONV_B,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2970 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2971
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2972 /* Click Conv B — archive-open fires, fetch held by convBFetchGate */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2973 await page.evaluate(id => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2974 for (const item of document.querySelectorAll('[data-conv-item]')) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2975 if (item._convId === id) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2976 item.querySelector('[data-conv-open]')?.click();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2977 break;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2978 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2979 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2980 }, CONV_B);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2981
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2982 /* 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
2983 await page.waitForTimeout(80);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2984
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2985 /* 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
2986 await page.goBack();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2987 await page.waitForTimeout(80);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2988
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2989 /* 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
2990 resolveConvBFetch();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2991 await page.waitForTimeout(300);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2992
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2993 /* currentConversationId must remain null (no aria-current item) */
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2994 const currentAriaItem = await page.evaluate(() => {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2995 const btn = document.querySelector('[data-conv-open][aria-current="true"]');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2996 return btn ? (btn.closest('[data-conv-item]')?._convId ?? null) : null;
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2997 });
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2998 assert.equal(
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
2999 currentAriaItem, null,
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3000 '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
3001 );
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3002
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3003 assert.deepEqual(pageErrors, [], 'no page errors in openSeq test');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3004 await context.close();
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3005 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3006 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3007
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3008 (async () => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3009 assert.ok(RUNFILES);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3010 assert.ok(WORKSPACE);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3011 const runfilesWorkspace = path.join(RUNFILES, WORKSPACE);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3012 const serverBinary = path.join(
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3013 runfilesWorkspace,
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
3014 'mrjunejune/mrjunejune_server_debug',
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3015 );
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3016 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
3017 const fakeSidecar = path.join(
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
3018 runfilesWorkspace,
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
3019 'mrjunejune/test/inference_bridge_fake_sidecar',
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
3020 );
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
3021 const tempDirectory = fs.mkdtempSync(
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
3022 path.join(os.tmpdir(), 'mrjunejune-theme-test-'),
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
3023 );
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3024 const chromiumPath = path.resolve(process.env.CHROMIUM_PATH);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3025 const serverLogs = [];
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3026 let server;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3027 let browser;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3028
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3029 try {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3030 port = await findFreePort();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3031 baseUrl = `http://127.0.0.1:${port}`;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3032 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
3033 assert.deepEqual(pngFiles, [], `PNG files leaked into runfiles: ${pngFiles}`);
258
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3034 for (const file of listFiles(siteRoot).filter(file =>
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3035 file.endsWith('.html')
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3036 )) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3037 const source = fs.readFileSync(file, 'utf8');
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3038 for (const primitive of source.matchAll(/<zen-button\b([^>]*)>/g)) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3039 assert.match(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3040 primitive[1],
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3041 /\bsize=["'](?:xs|sm|md|lg|xl)["']/,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3042 `${path.relative(siteRoot, file)} has an unsized zen-button`,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3043 );
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3044 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3045 assert.deepEqual(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3046 primitiveOwnershipViolations(source),
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3047 [],
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3048 `${path.relative(siteRoot, file)} violates primitive ownership`,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3049 );
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3050 }
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3051 for (const file of listFiles(siteRoot).filter(file =>
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3052 /\.(?:css|html|js)$/.test(file) &&
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3053 !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
3054 )) {
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3055 const source = fs.readFileSync(file, 'utf8');
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3056 assert.doesNotMatch(
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3057 source,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3058 /var\(\s*--zen-/,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3059 `${path.relative(siteRoot, file)} consumes a deprecated token`,
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3060 );
60a876c4587a [ui] Add semantic primitive ownership
MrJuneJune <me@mrjunejune.com>
parents: 256
diff changeset
3061 }
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3062
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3063 server = spawn(serverBinary, [], {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3064 cwd: runfilesWorkspace,
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
3065 env: {
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
3066 ...process.env,
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
3067 MRJUNEJUNE_PORT: port,
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
3068 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
3069 MRJUNEJUNE_INFERENCE_SIDECAR_PATH: fakeSidecar,
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
3070 MRJUNEJUNE_COPILOT_CLI_PATH: fakeSidecar,
265
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
3071 MRJUNEJUNE_ALLOW_GUEST_INFERENCE: '1',
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
3072 },
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3073 stdio: ['ignore', 'pipe', 'pipe'],
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3074 });
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3075 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
3076 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
3077 await waitForServer(server, serverLogs);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3078
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3079 const home = await (await fetch(baseUrl)).text();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3080 const dogGame = await (
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3081 await fetch(`${baseUrl}/public/dog-game.js`)
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3082 ).text();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3083 const manifest = await (
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3084 await fetch(`${baseUrl}/public/manifest.json`)
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3085 ).text();
242
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
3086 const serviceWorker = await (
256
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
3087 await fetch(`${baseUrl}/sw.js`)
242
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
3088 ).text();
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3089 for (const source of [home, dogGame, manifest]) {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3090 assert.doesNotMatch(source, /\.png(?:["')]|$)/i);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3091 }
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3092 assert.match(serviceWorker, /v37-network-first/);
256
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
3093 assert.match(
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
3094 await (
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
3095 await fetch(`${baseUrl}/public/pwa-register.js`)
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
3096 ).text(),
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
3097 /register\('\/sw\.js', \{ scope: '\/' \}\)/,
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
3098 );
242
543df0fe7168 [tools] Add full HLS player support
MrJuneJune <me@mrjunejune.com>
parents: 241
diff changeset
3099 assert.ok(serviceWorker.includes("startsWith('/tools/hls_player')"));
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
3100 assert.ok(serviceWorker.includes("url.hostname === 'localhost'"));
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
3101 assert.ok(serviceWorker.includes("url.hostname === '127.0.0.1'"));
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3102 assert.ok(serviceWorker.includes("DEVELOPMENT_SANDBOX_PATHS"));
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3103 assert.ok(serviceWorker.includes("'/public/component-sandbox'"));
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3104 assert.ok(serviceWorker.includes("'/public/mjj-modal.'"));
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3105 assert.ok(serviceWorker.includes('networkFirst(request, acceptsHtml)'));
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3106 assert.ok(serviceWorker.includes('staleWhileRevalidate(event, request)'));
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3107 assert.ok(serviceWorker.includes("fetch(request, { cache: 'no-cache' })"));
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3108 assert.doesNotMatch(
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3109 await (
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3110 await fetch(`${baseUrl}/public/pwa-register.js`)
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3111 ).text(),
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3112 /confirm\(/,
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3113 );
259
667156fcd3e3 Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents: 258
diff changeset
3114 assert.ok(!serviceWorker.includes("startsWith('/jrpg')"));
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3115
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3116 for (const asset of [
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3117 'sprite_shiba0.webp',
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3118 'dog-treat.webp',
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3119 'start-large.webp',
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3120 'icon-192.webp',
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3121 'vscode.webp',
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3122 ]) {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3123 const response = await fetch(`${baseUrl}/public/${asset}`);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3124 assert.equal(response.status, 200, asset);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3125 assert.ok((await response.arrayBuffer()).byteLength > 0, asset);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3126 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3127
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3128 browser = await chromium.launch({
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3129 executablePath: chromiumPath,
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3130 headless: true,
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3131 args: ['--no-sandbox'],
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3132 });
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3133 if (runsSuite('core')) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3134 const paper = await sampleTheme(browser, 'paper');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3135 const ink = await sampleTheme(browser, 'ink');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3136 const playful = await sampleTheme(browser, 'playful');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3137 const automatic = await sampleTheme(browser, 'auto');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3138 assert.equal(paper.rootTheme, 'paper');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3139 assert.equal(ink.rootTheme, 'ink');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3140 assert.equal(playful.rootTheme, 'playful');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3141 assert.equal(automatic.rootTheme, 'auto');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3142 assert.equal(paper.themeLabel, 'Paper');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3143 assert.equal(ink.themeLabel, 'Ink');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3144 assert.equal(playful.themeLabel, 'Playful');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3145 assert.equal(automatic.themeLabel, 'Auto');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3146 for (const sample of [paper, ink, playful, automatic]) {
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3147 assert.ok(sample.count > 0);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3148 assert.equal(sample.backgroundRepeat, 'no-repeat');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3149 assert.equal(sample.backgroundSize, 'cover');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3150 assert.equal(sample.bodyCoversViewport, true);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3151 assert.equal(sample.componentReady, true);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3152 assert.ok(sample.links > 0);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3153 assert.equal(sample.enhancedLinks, sample.pawLinks);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3154 assert.match(sample.fontFamily, /More/);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3155 assert.equal(sample.headerPaws, 0);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3156 assert.ok(sample.textContrast >= 4.5, JSON.stringify(sample));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3157 assert.equal(sample.mainBackground, 'rgba(0, 0, 0, 0)');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3158 assert.equal(sample.themeButtonBackground, 'rgba(0, 0, 0, 0)');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3159 assert.equal(sample.themeButtonBorder, '0px');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3160 assert.equal(sample.themeButtonShadow, 'none');
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3161 }
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3162 assert.ok(paper.luminance < 175, JSON.stringify(paper));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3163 assert.ok(playful.luminance < 175, JSON.stringify(playful));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3164 assert.ok(ink.luminance > 200, JSON.stringify(ink));
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3165 await testThemeCycle(browser);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3166 await testPlainField(browser);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3167 await testButtonScale(browser);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3168 await testDynamicButtonOwnership(browser);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3169 await testResumePrint(browser);
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents: 265
diff changeset
3170 await testComposerLab(browser);
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3171 await testModalSandbox(browser);
256
30c2196d03d4 [site] Integrate Zenbu themes and components
MrJuneJune <me@mrjunejune.com>
parents: 242
diff changeset
3172 }
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3173 if (runsSuite('jrpg')) await testJrpgPage(browser);
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3174 if (runsSuite('routing')) await testConversationRouting(browser);
265
056790c4fb0d add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents: 264
diff changeset
3175 if (runsSuite('greeting')) await testRoleGreetings(browser);
264
04fee26ecce0 add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents: 263
diff changeset
3176 if (runsSuite('hls')) await testHlsPlayer(browser, siteRoot);
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3177 } finally {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3178 if (browser) await browser.close();
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3179 await stopProcess(server);
260
1f9877b637e9 Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents: 259
diff changeset
3180 fs.rmSync(tempDirectory, { recursive: true, force: true });
241
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3181 }
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3182 })().catch(error => {
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3183 console.error(error.stack || error);
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3184 process.exitCode = 1;
9c2eec61a152 [assets] Generate site images as WebP with Bazel
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3185 });