annotate mrjunejune/test/theme_and_webp_test.js @ 279:b3b547563ec7

Add Google connector service and agent wiki Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code. Co-authored-by: Copilot <[email protected]> Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
author MrJuneJune <me@mrjunejune.com>
date Mon, 17 Aug 2026 22:22:36 -0700
parents e02e2036ef84
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 });