"""Regression checks for #6808: the boot script must not fabricate a theme choice.
`syncSettings` in static/boot.js deliberately lets the server win on a first
visit, because (its own comment) "empty (new-browser) state is indistinguishable
from a user who chose the defaults". The inline bootstrap in static/index.html
used to defeat that: it resolved a theme with
`localStorage.getItem('hermes-theme')||'dark'` and then wrote the result back
unconditionally, so a brand-new browser stored `hermes-theme=dark` before any
request was made. syncSettings then saw an "explicit" value, ignored the
server's SETTINGS_DEFAULTS, and POSTed the fabricated value back — making the
server-side appearance default unreachable for deployments that change it.
These cases pin the distinction the fix introduces, which nothing covered
before: ABSENT appearance state is not the same as EXPLICIT appearance state.
- both keys absent -> no setItem at all (and the dark pre-paint is UNCHANGED)
- either key present -> both values are normalised and persisted
- legacy names -> migration still happens, exactly as before
The third is the reason the guard is on the PAIR rather than per key. The write
is not pointless: it canonicalises legacy names (`solarized` -> dark+poseidon).
With `hermes-theme=solarized` and no `hermes-skin`, a per-key guard would never
write the derived skin and the mapping would be lost on the next load.
"""
import json
import re
import shutil
import subprocess
import tempfile
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parent.parent
INDEX_HTML = ROOT / "static" / "index.html"
NODE = shutil.which("node")
pytestmark = pytest.mark.skipif(
NODE is None,
reason="node is required to execute the appearance bootstrap harness",
)
def _bootstrap_script() -> str:
"""The inline appearance bootstrap, lifted out of index.html."""
html = INDEX_HTML.read_text(encoding="utf-8")
for m in re.finditer(r"", html, re.S):
body = m.group(1)
if "hermes-theme" in body and "legacy" in body and "skins" in body:
return body
raise AssertionError("appearance bootstrap