mathly / mathly2 /tests /serve.py
wzender's picture
Tests follow board work; home spec validates again (#11)
ca804b9 unverified
Raw History Blame Contribute Delete
2.18 kB
"""Run the app on a free port in a background thread, for browser tests."""
from __future__ import annotations
import socket
import threading
import time
from contextlib import contextmanager
import uvicorn
@contextmanager
def running(app):
with socket.socket() as probe:
probe.bind(("127.0.0.1", 0))
port = probe.getsockname()[1]
server = uvicorn.Server(uvicorn.Config(app, host="127.0.0.1", port=port, log_level="warning"))
thread = threading.Thread(target=server.run, daemon=True)
thread.start()
for _ in range(100):
if server.started:
break
time.sleep(0.05)
try:
yield f"http://127.0.0.1:{port}"
finally:
server.should_exit = True
thread.join(timeout=5)
def offline_formulas(page):
"""For tests that show no formulas: do not wait for the formula library from the network (a slow CDN made them time out)."""
page.route("**/mathjax@*/**", lambda route: route.abort())
return page
def only(bank, lessons):
"""A bank with just these lessons (and their skills), for tests that want a short path: every class now studies the whole bank."""
from mathly2.bank import Bank
keep = set(lessons)
return Bank({**bank.data, "units": [u for u in bank.lessons if u["id"] in keep], "skills": [s for s in bank.skills if s["unit"] in keep]})
# The board as if the student wrote the way on it (board-work): for tests about something else, a quiz or a test then takes a choice
# without drawing first. No picture is sent (pictureOf gives nothing). The board-work tests draw on the real board instead.
_BOARD_WRITTEN = """(() => {
const patch = b => { b.hasWork = () => true; b.workSig = () => "test"; b.pictureOf = async () => null; return b; };
if (window.MathlyBoard) { patch(window.MathlyBoard); return; }
let board;
Object.defineProperty(window, "MathlyBoard", { configurable: true, get: () => board, set: b => { board = patch(b); } });
})()"""
def board_written(page):
"""From now on (and after a reload) every board on the page counts as written on."""
page.add_init_script(_BOARD_WRITTEN)
page.evaluate(_BOARD_WRITTEN)
return page