add astra draft
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
"""Real Chromium DOM + real ASGI backend, bridged in-process (no network deployment test).
|
||||
|
||||
Requires playwright. Browser cookie/CSRF behavior is covered separately in test_api.py.
|
||||
The bridge uses TestClient's cookie jar and supplies the configured same-origin header.
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
import secrets
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / "backend" / "src"))
|
||||
from fastapi.testclient import TestClient
|
||||
from playwright.sync_api import sync_playwright
|
||||
from apc.api import Settings, create_app
|
||||
|
||||
|
||||
def main():
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
token = secrets.token_urlsafe(32)
|
||||
app = create_app(Settings(token, str(Path(directory) / "smoke.db")))
|
||||
with TestClient(app) as client, sync_playwright() as pw:
|
||||
browser = pw.chromium.launch(executable_path=os.environ.get("CHROMIUM_PATH") or None,
|
||||
args=["--no-sandbox"])
|
||||
page = browser.new_page(viewport={"width": 1280, "height": 900})
|
||||
errors = []
|
||||
page.on("pageerror", lambda error: errors.append(str(error)))
|
||||
def request(path, options):
|
||||
response = client.request(options.get("method", "GET"), path,
|
||||
content=options.get("body"), headers={"Content-Type": "application/json",
|
||||
"Origin": "http://localhost:8000"})
|
||||
return {"status": response.status_code, "body": response.text}
|
||||
page.expose_function("asgiRequest", request)
|
||||
html = client.get("/").text.replace('<script defer src="/static/app.js"></script>', "")
|
||||
html = html.replace('<link rel="stylesheet" href="/static/style.css">', "")
|
||||
page.set_content(html)
|
||||
page.add_style_tag(content=client.get("/static/style.css").text)
|
||||
page.evaluate("""() => { window.fetch = async (path, options = {}) => {
|
||||
const response = await window.asgiRequest(path, options);
|
||||
return new Response(response.body, {status: response.status,
|
||||
headers: {'Content-Type': 'application/json'}});
|
||||
}; }""")
|
||||
page.add_script_tag(content=client.get("/static/app.js").text)
|
||||
page.get_by_label("Administration token").fill(token)
|
||||
page.get_by_role("button", name="Sign in", exact=True).click()
|
||||
page.locator("#dashboard").wait_for(state="visible")
|
||||
for name in ("Example A", "Example B"):
|
||||
page.get_by_label("Display name", exact=True).fill(name)
|
||||
page.get_by_role("button", name="Add child", exact=True).click()
|
||||
page.get_by_role("heading", name=name, exact=True).wait_for()
|
||||
page.locator("#policy [name=daily_minutes]").fill("40")
|
||||
page.get_by_role("button", name="Save shared policy").click()
|
||||
page.get_by_text("Shared policy saved.", exact=False).wait_for()
|
||||
assert page.locator(".child").count() == 2
|
||||
first = page.locator(".child").first
|
||||
first.get_by_text("Individual exceptions", exact=True).click()
|
||||
first.locator("[name=daily_minutes]").fill("45")
|
||||
first.get_by_role("button", name="Save exceptions").click()
|
||||
page.get_by_text("Exceptions saved.", exact=False).wait_for()
|
||||
first = page.locator(".child").first
|
||||
assert "45 daily minutes" in first.inner_text()
|
||||
first.get_by_role("button", name="Pair phone").click()
|
||||
page.locator("#code-dialog").wait_for(state="visible")
|
||||
code = page.locator("#issued-code").inner_text()
|
||||
paired = client.post("/v1/pair", json={"code": code, "name": "Smoke test"}).json()
|
||||
headers = {"Authorization": f"Bearer {paired['token']}"}
|
||||
challenge = client.post("/v1/device/challenges", headers=headers).json()
|
||||
answers = []
|
||||
for q in challenge["questions"]:
|
||||
a, op, b = q["prompt"].split()
|
||||
answers.append({"question_id": q["id"], "answer": int(a) + int(b) if op == "+" else int(a) - int(b)})
|
||||
result = client.post(f"/v1/device/challenges/{challenge['id']}/submit",
|
||||
headers=headers, json={"answers": answers})
|
||||
assert result.json()["awarded_minutes"] == 10
|
||||
page.get_by_role("button", name="Close", exact=True).click()
|
||||
page.get_by_role("button", name="Refresh status").click()
|
||||
page.get_by_text("45 daily minutes + 10 earned today", exact=False).wait_for()
|
||||
if os.environ.get("APC_SCREENSHOT"):
|
||||
page.screenshot(path=os.environ["APC_SCREENSHOT"], full_page=True)
|
||||
page.get_by_role("button", name="Sign out").click()
|
||||
page.locator("#login-panel").wait_for(state="visible")
|
||||
assert not errors, errors
|
||||
browser.close()
|
||||
print("Browser/ASGI smoke passed: login, two children, policy, override, pairing, reward, logout")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user