Optional sections: checkpoint tracker, admin/roles, login page

- dashboard.html: each section sits in OPTIONAL:<name> BEGIN/END blocks in
  the style, markup and script, with sample answers so a page with no bot
  shows it working. Core change: setUser records the role on <body>, so CSS
  hides admin-only parts from operators.
- templates/sections.py keeps the chosen sections and deletes the rest,
  markers included; it stops on a broken marker.
- templates/sections.md: what each section needs from the host (events,
  actions, desktop slot snippets, the role re-check, the login hand-off).
- SKILL.md step 5 asks one multi-select question and runs sections.py.
- Page check: checkpoint states, admin visibility by role and assign/remove,
  login theme and hand-off to auth or the stub. Cases skip on a generated
  page without the section; the template must carry all three. The harness
  signs in when the page has a login screen.
- tests/test_sections.py: no sections leave no trace, and that page still
  passes the page check.
- Eval runner: a-empty-sections variant (all three) and per-section checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
VasanthandClaude Opus 5.5 committed 2026-10-16 14:31:25 +05:30
1 parent 3eb3fdf00e
commit 9a5b95448d
10 files changed
+536 -10

No files matched your search

+146
View File
@@ -0,0 +1,146 @@
"""Optional sections (see templates/sections.md). On a generated page, a case skips when the
page was built without its section. The template itself must carry every section."""
import os
import re
import pytest
from playwright.sync_api import expect
from test_contract import colour_of, open_tab
def need(locator, section):
if not locator.count():
if not os.environ.get("PAGE_CHECK_HTML"):
pytest.fail(f"the template has no {section}")
pytest.skip(f"page built without the {section}")
return locator
def fits_width(page, locator):
box = locator.bounding_box()
return box["x"] >= 0 and box["x"] + box["width"] <= page.viewport_size["width"]
CP_SHOWS = {"pending": ("Pending", "grey"), "active": ("In progress", "amber"),
"done": ("Done", "green"), "stuck": ("Stuck", "red")}
def test_checkpoint_boxes_show_each_state(page, push):
track = need(page.get_by_role("list", name="Checkpoints", include_hidden=True), "checkpoint tracker")
open_tab(page, "Run")
boxes = track.get_by_role("listitem")
n = boxes.count()
assert n >= 2, "the tracker needs at least two checkpoints"
def expect_boxes(*kinds):
for i, kind in enumerate(kinds):
label, colour = CP_SHOWS[kind]
expect(boxes.nth(i)).to_have_text(re.compile(rf"^\s*{i + 1}(?!\d).*{label}\s*$"))
assert colour_of(boxes.nth(i)) == colour, (i + 1, kind)
expect_boxes(*["pending"] * n)
push("cpstate", {"kind": "active", "cp": 2}) # earlier boxes are done, later ones pending
expect_boxes("done", "active", *["pending"] * (n - 2))
push("cpstate", {"kind": "stuck", "cp": 2})
expect_boxes("done", "stuck")
push("cpstate", {"kind": "done", "cp": 2})
expect_boxes("done", "done")
push("cpstate", {"kind": "pending", "cp": 2})
expect_boxes("done", "pending")
assert fits_width(page, boxes.last)
ADA = {"username": "ada", "emp_id": "E1", "role": "admin"}
OLIVE = {"username": "olive", "emp_id": "E2", "role": "operator"}
def admin_nav(page):
return need(page.get_by_role("navigation").get_by_role("button", name="Admin", exact=True, include_hidden=True),
"admin screen")
def test_admin_screen_only_for_admins(page, push):
nav = admin_nav(page)
push("set_user", OLIVE)
expect(nav).to_be_hidden()
push("set_user", ADA)
expect(nav).to_be_visible()
nav.click()
users = page.get_by_role("table", name="Users with access")
push("admin_data", {"rows": [ADA, OLIVE]})
rows = users.locator("tbody").get_by_role("row")
expect(rows).to_have_count(2)
expect(rows.nth(1)).to_contain_text("olive")
expect(rows.nth(1)).to_contain_text(re.compile("operator", re.I))
push("set_user", OLIVE) # operators see neither the nav item nor the screen
expect(nav).to_be_hidden()
expect(users).to_be_hidden()
def test_admin_assigns_and_removes_roles(page, push):
nav = admin_nav(page)
push("set_user", ADA)
nav.click()
sample = page.evaluate("SAMPLE_DATA")
form = page.get_by_role("form", name="Assign access")
form.get_by_role("textbox", name="Username or employee ID").fill("grace")
form.get_by_role("combobox", name="Role").select_option("admin")
form.get_by_role("button", name="Assign").click()
rows = page.get_by_role("table", name="Users with access").locator("tbody").get_by_role("row")
if not sample: # wired page: the host answers with fresh admin_data
assert ["assign_role", "grace", "admin"] in page.evaluate("window.__calls")
push("admin_data", {"rows": [ADA, {"username": "grace", "emp_id": "", "role": "admin"}]})
grace = rows.filter(has_text="grace")
expect(grace).to_contain_text(re.compile("admin", re.I))
grace.get_by_role("button", name="Remove").click()
if not sample:
assert ["remove_role", "grace"] in page.evaluate("window.__calls")
push("admin_data", {"rows": [ADA]})
expect(grace).to_have_count(0)
def login_form(page):
return need(page.get_by_role("form", name="Sign in", include_hidden=True), "login page")
def sign_out(page):
page.get_by_role("button", name="Sign out", exact=True).click()
def light_text(locator):
rgb = re.findall(r"\d+", locator.evaluate("el => getComputedStyle(el).color"))[:3]
return sum(int(x) for x in rgb) / 3 > 128
def test_login_page_renders_in_the_theme(page, request):
form = login_form(page)
sign_out(page)
expect(form).to_be_visible()
assert fits_width(page, form)
assert light_text(form) == (request.node.callspec.params["page"] == "dark")
expect(form.get_by_role("button", name="Sign in")).to_be_visible()
def test_login_hands_off_to_auth_or_stub(page, push):
form = login_form(page)
sample = page.evaluate("SAMPLE_DATA")
sign_out(page)
form.get_by_role("textbox", name="Username").fill("alice")
form.get_by_label("Password").fill("secret")
form.get_by_role("button", name="Sign in").click()
if sample: # no auth yet: the stub signs anyone in
expect(form).to_be_hidden()
expect(page.get_by_text("alice", exact=True)).to_have_count(1)
sign_out(page)
else: # the host checks it with the project's auth
calls = page.evaluate("window.__calls")
assert ["logout"] in calls and ["login", "alice", "secret"] in calls
push("login_result", {"ok": False, "msg": "Wrong password"})
expect(form.get_by_role("alert")).to_have_text("Wrong password")
expect(form).to_be_visible()
push("login_result", {"ok": True, "user": {"username": "bob", "emp_id": "7", "role": "operator"}})
expect(form).to_be_hidden()
expect(page.get_by_text("bob", exact=True)).to_have_count(1)