Expand browser editor runtime and LED simulation workflows.

Add Docker deployment support, richer Selenium/LED pattern tests, in-browser diagnostics, responsive UI improvements, and 16x16 panel simulation tooling to speed iteration and hardware-style prototyping.

Made-with: Cursor
This commit is contained in:
2026-05-01 20:24:05 +12:00
parent f204109a84
commit e4c811f51d
30 changed files with 1478 additions and 60 deletions

View File

@@ -0,0 +1,44 @@
import importlib.util
from pathlib import Path
def _load_patterns_module():
repo_root = Path(__file__).resolve().parents[1]
module_path = repo_root / "workspace" / "code" / "led_patterns.py"
spec = importlib.util.spec_from_file_location("led_patterns", module_path)
module = importlib.util.module_from_spec(spec)
assert spec is not None and spec.loader is not None
spec.loader.exec_module(module)
return module
def test_rainbow_frame_shape_and_bounds():
patterns = _load_patterns_module()
frame = patterns.rainbow_frame(12, 3)
assert len(frame) == 12
for color in frame:
assert len(color) == 3
assert all(0 <= c <= 255 for c in color)
def test_chase_frame_has_head_and_tail():
patterns = _load_patterns_module()
frame = patterns.chase_frame(8, 5, color=(10, 20, 30), tail=(1, 2, 3))
assert len(frame) == 8
assert frame[5] == (10, 20, 30)
assert frame[4] == (1, 2, 3)
assert sum(1 for c in frame if c != (0, 0, 0)) == 2
def test_twinkle_frame_is_deterministic_for_same_inputs():
patterns = _load_patterns_module()
a = patterns.twinkle_frame(20, frame=9, seed=777, sparkles=4)
b = patterns.twinkle_frame(20, frame=9, seed=777, sparkles=4)
assert a == b
def test_twinkle_frame_varies_between_frames():
patterns = _load_patterns_module()
a = patterns.twinkle_frame(20, frame=1, seed=777, sparkles=4)
b = patterns.twinkle_frame(20, frame=2, seed=777, sparkles=4)
assert a != b

View File

@@ -7,6 +7,9 @@ import urllib.error
import urllib.request
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.ui import WebDriverWait
pytest.importorskip("selenium.webdriver")
@@ -46,3 +49,24 @@ def test_home_page_title(driver):
)
driver.get(f"{base}/")
assert "Python Editor" in driver.title
@pytest.mark.selenium
def test_editor_page_loads_core_controls(driver):
base = os.environ.get("SELENIUM_BASE_URL", "http://127.0.0.1:8080").rstrip("/")
if not _server_reachable(base):
pytest.skip(
f"No server at {base}. In another terminal run: "
"pipenv run dev (then re-run this test, or set SELENIUM_BASE_URL)."
)
driver.get(f"{base}/editor")
# If the app is configured with AUTH_ENABLED=true, unauthenticated requests redirect to /login.
if "/login" in (driver.current_url or ""):
pytest.skip("Editor requires login; set AUTH_ENABLED=false for this Selenium smoke test.")
wait = WebDriverWait(driver, 10)
wait.until(ec.presence_of_element_located((By.ID, "run-btn")))
wait.until(ec.presence_of_element_located((By.ID, "stop-btn")))
wait.until(ec.presence_of_element_located((By.ID, "file-tree")))