diff mrjunejune/test/theme_and_webp_test.js @ 256:30c2196d03d4

[site] Integrate Zenbu themes and components Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Tue, 04 Aug 2026 16:49:01 -0700
parents 543df0fe7168
children 60a876c4587a
line wrap: on
line diff
--- a/mrjunejune/test/theme_and_webp_test.js	Tue Aug 04 15:12:18 2026 -0700
+++ b/mrjunejune/test/theme_and_webp_test.js	Tue Aug 04 16:49:01 2026 -0700
@@ -110,10 +110,35 @@
         data[index + 1] * 0.7152 +
         data[index + 2] * 0.0722;
     }
+    const channels = value => value.match(/\d+(?:\.\d+)?/g)
+      .slice(0, 3)
+      .map(Number);
+    const colorLuminance = value => {
+      const converted = channels(value).map(channel => {
+        const normalized = channel / 255;
+        return normalized <= 0.04045
+          ? normalized / 12.92
+          : ((normalized + 0.055) / 1.055) ** 2.4;
+      });
+      return converted[0] * 0.2126 +
+        converted[1] * 0.7152 +
+        converted[2] * 0.0722;
+    };
+    const bodyStyle = getComputedStyle(document.body);
+    const foreground = colorLuminance(bodyStyle.color);
+    const background = colorLuminance(
+      getComputedStyle(document.querySelector('main')).backgroundColor,
+    );
     return {
+      cardCount: document.querySelectorAll('.site-link-grid zen-card').length,
+      componentReady: Boolean(customElements.get('zen-card')),
       count,
+      fontFamily: getComputedStyle(document.body).fontFamily,
       luminance: count ? luminance / count : 0,
-      rootClass: document.documentElement.className,
+      textContrast: (Math.max(foreground, background) + 0.05) /
+        (Math.min(foreground, background) + 0.05),
+      rootTheme: document.documentElement.dataset.zenTheme || 'auto',
+      themeLabel: document.querySelector('#themeName')?.textContent,
     };
   });
 
@@ -122,6 +147,27 @@
   return sample;
 }
 
+async function testThemeCycle(browser) {
+  const context = await browser.newContext({ colorScheme: 'light' });
+  const page = await context.newPage();
+  await page.goto(baseUrl, { waitUntil: 'networkidle' });
+  const expected = ['paper', 'ink', 'playful', 'auto'];
+  for (const theme of expected) {
+    await page.locator('#themeToggle').click();
+    assert.equal(
+      await page.evaluate(() =>
+        document.documentElement.dataset.zenTheme || 'auto'
+      ),
+      theme,
+    );
+    assert.equal(
+      await page.evaluate(() => localStorage.getItem('theme-preference')),
+      theme,
+    );
+  }
+  await context.close();
+}
+
 async function testHlsPlayer(browser, siteRoot) {
   const page = await browser.newPage();
   const errors = [];
@@ -395,12 +441,18 @@
       await fetch(`${baseUrl}/public/manifest.json`)
     ).text();
     const serviceWorker = await (
-      await fetch(`${baseUrl}/public/sw.js`)
+      await fetch(`${baseUrl}/sw.js`)
     ).text();
     for (const source of [home, dogGame, manifest]) {
       assert.doesNotMatch(source, /\.png(?:["')]|$)/i);
     }
-    assert.match(serviceWorker, /v4-hlsjs/);
+    assert.match(serviceWorker, /v5-zenbu-themes/);
+    assert.match(
+      await (
+        await fetch(`${baseUrl}/public/pwa-register.js`)
+      ).text(),
+      /register\('\/sw\.js', \{ scope: '\/' \}\)/,
+    );
     assert.ok(serviceWorker.includes("startsWith('/tools/hls_player')"));
 
     for (const asset of [
@@ -420,12 +472,29 @@
       headless: true,
       args: ['--no-sandbox'],
     });
-    const light = await sampleTheme(browser, 'light');
-    const dark = await sampleTheme(browser, 'dark');
-    assert.ok(light.count > 0);
-    assert.ok(dark.count > 0);
-    assert.ok(light.luminance < 175, JSON.stringify(light));
-    assert.ok(dark.luminance > 200, JSON.stringify(dark));
+    const paper = await sampleTheme(browser, 'paper');
+    const ink = await sampleTheme(browser, 'ink');
+    const playful = await sampleTheme(browser, 'playful');
+    const automatic = await sampleTheme(browser, 'auto');
+    assert.equal(paper.rootTheme, 'paper');
+    assert.equal(ink.rootTheme, 'ink');
+    assert.equal(playful.rootTheme, 'playful');
+    assert.equal(automatic.rootTheme, 'auto');
+    assert.equal(paper.themeLabel, 'Paper');
+    assert.equal(ink.themeLabel, 'Ink');
+    assert.equal(playful.themeLabel, 'Playful');
+    assert.equal(automatic.themeLabel, 'Auto');
+    for (const sample of [paper, ink, playful, automatic]) {
+      assert.ok(sample.count > 0);
+      assert.equal(sample.componentReady, true);
+      assert.equal(sample.cardCount, 4);
+      assert.match(sample.fontFamily, /More/);
+      assert.ok(sample.textContrast >= 4.5, JSON.stringify(sample));
+    }
+    assert.ok(paper.luminance < 175, JSON.stringify(paper));
+    assert.ok(playful.luminance < 175, JSON.stringify(playful));
+    assert.ok(ink.luminance > 200, JSON.stringify(ink));
+    await testThemeCycle(browser);
     await testHlsPlayer(browser, siteRoot);
   } finally {
     if (browser) await browser.close();