mirror of
https://github.com/Niko1221/Strata.git
synced 2026-11-07 06:15:58 -10:00
One button in the header of every tab: Load while the model is unloaded, Unload otherwise. It calls POST /load and POST /unload (the server already had both, for its own page only). Unload asks first and never interrupts a turn: the button is off while an answer is being written, an image is made or a request is queued. The pill and the Monitor say Unloaded / Loading / Unloading, a message or an image on an unloaded model shows Loading, and a poll that started before the POST cannot flip the button back (the POST's state is held until a later poll agrees). On a phone the pill's text is the first thing the header row gives up (it measures the row, not a fixed width), so Load/Unload and the theme button stay on the screen from 320 px. Browser tests (tools/webtest/browser_test.mjs): unload with its question, load back, declining, not while answering, a message that loads, the header at 320 to 640 px. Ported by hand from PR #3550 by Sakurai Momoka (sakuumomo); the texts now go through the page's translation catalog. Co-authored-by: Sakurai Momoka <[email protected]>
69 lines
3.0 KiB
Python
69 lines
3.0 KiB
Python
"""serve/test_web_load_unload.py - the web page's header carries the Load / Unload control (#3550, by sakuumomo).
|
|
|
|
Pins, as text: index.html holds the header button and the Monitor's "Unloaded" badge; app.js wires the button to POST /load
|
|
and POST /unload, holds the POST's state until a later poll agrees, answers a 401 with the key copy, and refits the header
|
|
row only when its text changed (the per-second poll does not force a layout). The behaviour itself, in a real browser, is in
|
|
tools/webtest/browser_test.mjs ("load/unload: ...").
|
|
|
|
python -m unittest serve.test_web_load_unload -v
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import shutil
|
|
import subprocess
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
WEB = Path(__file__).resolve().parent / "web"
|
|
|
|
|
|
class WebLoadUnloadMarkup(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
cls.html = (WEB / "index.html").read_text(encoding="utf-8")
|
|
cls.js = (WEB / "app.js").read_text(encoding="utf-8")
|
|
cls.css = (WEB / "app.css").read_text(encoding="utf-8")
|
|
|
|
def test_header_button_and_monitor_badge(self):
|
|
self.assertIn('id="unload-btn"', self.html)
|
|
self.assertIn('data-s="unloaded"', self.html)
|
|
self.assertLess(self.html.index('id="unload-btn"'), self.html.index('id="theme-btn"')) # in the header row
|
|
|
|
def test_button_posts_load_and_unload(self):
|
|
self.assertIn('$("unload-btn").onclick', self.js)
|
|
self.assertIn('fetch(loadingNow ? "load" : "unload", {method: "POST", headers: headers(true), body: "{}"})', self.js)
|
|
|
|
def test_unload_asks_first_and_never_interrupts_a_turn(self):
|
|
self.assertIn("confirm(tr(\"model.confirmUnload\"", self.js)
|
|
self.assertIn("turnBlocksUnload(live)", self.js)
|
|
self.assertIn("function turnBlocksUnload(live)", self.js)
|
|
|
|
def test_401_gets_the_key_copy(self):
|
|
# The control POST answers a 401 the way poll and send do, not with a bare HTTP line.
|
|
self.assertIn('r.status === 401 ? tr("toast.keyAbout2"', self.js)
|
|
|
|
def test_poll_hold_until_a_poll_agrees(self):
|
|
self.assertIn("metricsHold = {state, after: metricsEpoch};", self.js)
|
|
self.assertIn("function metricsAgree(live, state)", self.js)
|
|
|
|
def test_header_refits_only_on_changed_text(self):
|
|
# The per-second poll re-sets the pill; the fit runs when its text actually changed.
|
|
self.assertIn("if (text !== lastPillText) { lastPillText = text; fitHeader(); }", self.js)
|
|
|
|
def test_the_header_row_keeps_the_buttons_on_a_phone(self):
|
|
self.assertIn("#unload-btn", self.css)
|
|
self.assertIn(".st-header--clip #pill-text", self.css)
|
|
for width in ("955px", "457px", "382px"):
|
|
self.assertIn(f"@media (max-width: {width})", self.css)
|
|
|
|
|
|
@unittest.skipUnless(shutil.which("node"), "node is not installed")
|
|
class WebLoadUnloadParses(unittest.TestCase):
|
|
def test_app_js_parses(self):
|
|
r = subprocess.run(["node", "--check", str(WEB / "app.js")], capture_output=True, text=True)
|
|
self.assertEqual(r.returncode, 0, r.stderr)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|