Files
hermes-webui/tests/test_issue2462_theme_i18n.py
T
nesquena-hermesandt3chn0pr13st c0d86db5a8 Release v0.51.242 — Release HJ (stage-q14) (#3500)
## Release v0.51.242 — Release HJ (stage-q14)

UX-approved via Telegram (Nathan — dark/light/mobile screenshots).

### Added
| PR | Author | Feature |
|----|--------|---------|
| #3440 | @t3chn0pr13st | **Graphite appearance skin** — a quiet, neutral-gray "workbench" alternative to the default gold/cream. Selectable from Settings → Appearance and `/theme skin graphite`. Both light + dark palettes on the existing CSS-variable token system; tightened typography, shadows, active-sidebar spacing, code-block framing. |

### Why it's safe
- **Fully scoped + additive**: every new CSS rule (and every `!important`) is under `[data-skin="graphite"]` — Codex verified zero bleed into the default appearance or other skins. `api/config.py` keeps the default skin as `default` and only *adds* `graphite` to the allowed set. No i18n keys dropped (only the `/theme` help string gains `graphite`).
- Opt-in; a user has to select it. Default experience unchanged.

### Test-robustness fix (absorbed)
The new graphite scoped selectors (e.g. `:root[data-skin="graphite"] .session-item.active .session-time{…}`) appear in `style.css` *before* the canonical unscoped rules, which broke 3 naive first-occurrence CSS-contract tests (`test_issue677` scroll-btn-overlay, `test_issue856_pinned_indicator_layout`, `test_workspace_panel_session_list`). Fixed those 3 to anchor on the canonical **unscoped** rule (start-of-line regex) instead of the first `.selector` match — robust against this and future skins. Verified they still pass on clean master CSS (invariant preserved, not weakened).

### Gate
- Full pytest suite: **7517 passed, 9 skipped, 3 xpassed, 0 failed**
- ESLint runtime gate: CLEAN · ruff: CLEAN · browser-smoke: CLEAN
- Codex (regression): **SAFE TO SHIP** (verified all CSS scoped, default skin unchanged, no i18n key loss)
- Vision-verified dark + light + mobile; UX-approved by Nathan via Telegram

Co-authored-by: t3chn0pr13st <t3chn0pr13st@users.noreply.github.com>
2026-06-03 16:46:53 -07:00

44 lines
1.7 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Regression coverage for #2462 stale /theme i18n help strings."""
from pathlib import Path
import re
ROOT = Path(__file__).resolve().parents[1]
I18N_JS = (ROOT / "static" / "i18n.js").read_text(encoding="utf-8")
def _locale_block(locale: str) -> str:
# Locale keys are mostly bare identifiers, but zh-Hant is quoted. Match the
# requested block up to the next top-level locale block or the LOCALES close.
match = re.search(
rf"\n\s*['\"]?{re.escape(locale)}['\"]?:\s*\{{(?P<body>.*?)(?=\n\s*['\"]?[a-z][\w-]*['\"]?:\s*\{{|\n\}};)",
I18N_JS,
re.S,
)
assert match, f"locale block {locale!r} not found"
return match.group("body")
def _literal_value(block: str, key: str) -> str:
match = re.search(rf"\n\s*{re.escape(key)}:\s*'(?P<value>(?:\\'|[^'])*)',", block)
assert match, f"{key!r} not found in locale block"
return match.group("value")
def test_theme_command_help_mentions_current_theme_and_skin_values():
"""Every /theme help string should describe the current Theme × Skin contract."""
required_fragments = (
"system/dark/light",
"default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast",
)
for locale in ("en", "it", "ja", "ru", "es", "de", "zh", "zh-Hant", "pt", "ko", "fr", "tr"):
value = _literal_value(_locale_block(locale), "cmd_theme")
for fragment in required_fragments:
assert fragment in value, f"{locale} cmd_theme missing {fragment!r}: {value!r}"
def test_french_theme_usage_uses_actual_slash_command_with_space():
fr_theme_usage = _literal_value(_locale_block("fr"), "theme_usage")
assert fr_theme_usage == "Utilisation : /theme "
assert "/thème" not in fr_theme_usage