195 lines
7.6 KiB
Python
Raw Normal View History

2026-07-26 14:57:18 +02:00
# retoor <retoor@molodetz.nl>
import requests
from tests.conftest import BASE_URL
JSON = {"Accept": "application/json"}
LAYOUT = ".feed-layout"
LEFT = ".feed-layout > .sidebar-card"
CENTRE = ".feed-layout > .feed-main"
RIGHT = ".feed-layout > .feed-right"
NAV_ENTRY = ".topnav-link[href='/quizzes']"
NEW_QUIZ_BUTTON = ".quiz-actions a[href='/quizzes/new']"
DEVII_BUTTON = ".quiz-actions button[data-devii-open]"
SCOREBOARD = ".quiz-scoreboard-card"
def _seed_quiz(title="Hub e2e quiz"):
session = requests.Session()
name = f"hub{abs(hash(title)) % 10**9}"
session.post(
f"{BASE_URL}/auth/signup",
data={
"username": name,
"email": f"{name}@t.dev",
"password": "secret123",
"confirm_password": "secret123",
},
allow_redirects=True,
)
slug = session.post(
f"{BASE_URL}/quizzes/create", data={"title": title, "description": "d"}, headers=JSON
).json()["data"]["slug"]
session.post(
f"{BASE_URL}/quizzes/{slug}/questions",
data={
"kind": "single_choice",
"prompt": "Which journal mode allows concurrent readers?",
"points": 2,
"options": "DELETE\nWAL",
"correct_indexes": "1",
},
headers=JSON,
)
session.post(f"{BASE_URL}/quizzes/{slug}/publish", headers=JSON)
return slug
def test_the_hub_renders_the_three_column_layout(page, app_server):
_seed_quiz("Layout e2e quiz")
page.goto(f"{BASE_URL}/quizzes", wait_until="domcontentloaded")
page.locator(LAYOUT).wait_for(state="visible")
assert page.locator(LEFT).count() == 1
assert page.locator(CENTRE).count() == 1
assert page.locator(RIGHT).count() == 1
def test_the_hub_has_a_visible_heading(page, app_server):
page.goto(f"{BASE_URL}/quizzes", wait_until="domcontentloaded")
heading = page.locator("h1.quiz-page-title")
heading.wait_for(state="visible")
assert heading.inner_text().strip() == "Quizzes"
def test_the_nav_entry_is_visible_to_a_guest_and_active(page, app_server):
page.goto(f"{BASE_URL}/quizzes", wait_until="domcontentloaded")
entry = page.locator(NAV_ENTRY)
entry.wait_for(state="visible")
assert "active" in (entry.get_attribute("class") or "")
def test_a_guest_sees_disabled_create_controls(page, app_server):
page.goto(f"{BASE_URL}/quizzes", wait_until="domcontentloaded")
page.locator(".quiz-actions").wait_for(state="visible")
assert page.locator(NEW_QUIZ_BUTTON).get_attribute("aria-disabled") == "true"
assert page.locator(DEVII_BUTTON).is_disabled()
def test_a_guest_still_sees_the_list_and_the_scoreboard(page, app_server):
_seed_quiz("Guest visible quiz")
page.goto(f"{BASE_URL}/quizzes", wait_until="domcontentloaded")
page.locator(SCOREBOARD).wait_for(state="visible")
assert page.locator(".quiz-card").count() >= 1
def test_a_member_sees_enabled_create_controls(alice):
page, _ = alice
page.goto(f"{BASE_URL}/quizzes", wait_until="domcontentloaded")
page.locator(NEW_QUIZ_BUTTON).wait_for(state="visible")
assert page.locator(NEW_QUIZ_BUTTON).get_attribute("aria-disabled") is None
assert page.locator(DEVII_BUTTON).is_enabled()
def test_a_member_sees_the_personal_filters(alice):
page, _ = alice
page.goto(f"{BASE_URL}/quizzes", wait_until="domcontentloaded")
page.locator(".sidebar-nav").wait_for(state="visible")
for target in ("todo", "done", "mine", "drafts"):
assert page.locator(f".sidebar-link[href='/quizzes?filter={target}']").count() == 1
def test_a_guest_sees_only_the_all_filter(page, app_server):
page.goto(f"{BASE_URL}/quizzes", wait_until="domcontentloaded")
page.locator(".sidebar-nav").wait_for(state="visible")
assert page.locator(".sidebar-link[href='/quizzes?filter=todo']").count() == 0
assert page.locator(".sidebar-link[href='/quizzes?filter=all']").count() == 1
def test_a_quiz_card_shows_its_state_badge(alice):
page, _ = alice
slug = _seed_quiz("Badge e2e quiz")
page.goto(f"{BASE_URL}/quizzes", wait_until="domcontentloaded")
card = page.locator(f".quiz-card:has(a[href='/quizzes/{slug}'])").first
card.wait_for(state="visible")
assert card.locator(".quiz-state-todo").count() == 1
def test_a_quiz_card_shows_its_meta_chips(page, app_server):
slug = _seed_quiz("Meta chips e2e quiz")
page.goto(f"{BASE_URL}/quizzes", wait_until="domcontentloaded")
card = page.locator(f".quiz-card:has(a[href='/quizzes/{slug}'])").first
card.wait_for(state="visible")
assert "1 questions" in card.inner_text()
assert "2 points" in card.inner_text()
def test_the_search_box_filters_the_list(page, app_server):
slug = _seed_quiz("Unmistakable pelican quiz")
page.goto(f"{BASE_URL}/quizzes?search=pelican", wait_until="domcontentloaded")
page.locator(".feed-posts").wait_for(state="visible")
assert page.locator(f".quiz-card:has(a[href='/quizzes/{slug}'])").count() == 1
def test_the_new_quiz_button_opens_the_create_form(alice):
page, _ = alice
page.goto(f"{BASE_URL}/quizzes", wait_until="domcontentloaded")
page.locator(NEW_QUIZ_BUTTON).click()
page.wait_for_url("**/quizzes/new", wait_until="domcontentloaded")
page.locator("form.quiz-form").wait_for(state="visible")
def test_the_devii_button_seeds_the_terminal_without_sending(alice):
page, _ = alice
page.goto(f"{BASE_URL}/quizzes", wait_until="domcontentloaded")
trigger = page.locator(DEVII_BUTTON)
trigger.wait_for(state="visible")
prompt = trigger.get_attribute("data-devii-prompt")
assert prompt and "import_quiz" in prompt
trigger.click()
terminal_input = page.locator("devii-terminal .devii-input")
terminal_input.wait_for(state="visible", timeout=10000)
assert terminal_input.input_value() == prompt
assert page.locator("devii-terminal .devii-line-user").count() == 0
page.evaluate("window.app && window.app.devii && window.app.devii.close()")
page.evaluate("window.localStorage.clear()")
def test_opening_a_card_reaches_the_detail_page(page, app_server):
slug = _seed_quiz("Card link e2e quiz")
page.goto(f"{BASE_URL}/quizzes", wait_until="domcontentloaded")
page.locator(f".quiz-card a.card-link[href='/quizzes/{slug}']").first.click()
page.wait_for_url(f"**/quizzes/{slug}", wait_until="domcontentloaded")
page.locator("h1.quiz-detail-title").wait_for(state="visible")
def test_the_detail_page_shows_the_stats_strip(page, app_server):
slug = _seed_quiz("Stats strip e2e quiz")
page.goto(f"{BASE_URL}/quizzes/{slug}", wait_until="domcontentloaded")
page.locator(".quiz-stats-strip").wait_for(state="visible")
assert page.locator(".quiz-stat").count() == 5
def test_the_detail_page_offers_a_start_button_to_a_member(alice):
page, _ = alice
slug = _seed_quiz("Start button e2e quiz")
page.goto(f"{BASE_URL}/quizzes/{slug}", wait_until="domcontentloaded")
button = page.locator(".quiz-detail-actions button:has-text('Start quiz')")
button.wait_for(state="visible")
assert button.is_enabled()
def test_the_detail_page_disables_start_for_a_guest(page, app_server):
slug = _seed_quiz("Guest start e2e quiz")
page.goto(f"{BASE_URL}/quizzes/{slug}", wait_until="domcontentloaded")
button = page.locator(".quiz-detail-actions button:has-text('Start quiz')")
button.wait_for(state="visible")
assert button.is_disabled()
def test_the_detail_page_carries_a_comment_section(page, app_server):
slug = _seed_quiz("Comment section e2e quiz")
page.goto(f"{BASE_URL}/quizzes/{slug}", wait_until="domcontentloaded")
page.locator(".comments-section").wait_for(state="visible")