mathly / tests /test_science.py
3v324v23's picture
feat(science): implement interactive riddle voting system with CSS animations
a4bc651
Raw History Blame Contribute Delete
4.55 kB
"""The science path and its class vote (app/science.py)."""
import copy
import pytest
from fastapi.testclient import TestClient
from app.main import create_app
from app.science import problems, science
A, B, C = "voter-aaaa", "voter-bbbb", "voter-cccc"
@pytest.fixture
def client():
return TestClient(create_app())
def open_room(client):
r = client.post("/api/science/rooms", json={"skill": "rocket"})
assert r.status_code == 200
body = r.json()
return body["code"], {"X-Host": body["host_key"]}
def vote(client, code, voter, choice, n=1):
return client.post(f"/api/science/rooms/{code}/vote", json={"voter": voter, "choice": choice, "n": n})
def test_the_science_path_is_valid_and_hides_answers(client):
assert problems(science()) == []
graph = client.get("/api/science").json()
assert graph["subject"] == "מדעים"
assert [u["name"] for u in graph["units"]] == ["חידות"]
assert [s["name"] for s in graph["skills"]] == ["טיל"]
assert graph["skills"][0]["riddles"] == 3 # counted, not sent: they hold the answers
assert "flies" not in str(graph)
def test_a_riddle_needs_exactly_one_answer_that_flies():
broken = copy.deepcopy(science())
for c in broken["skills"][0]["riddles"][0]["choices"]:
c["outcome"] = "stuck"
assert "rocket riddle 1: exactly one choice must fly" in problems(broken)
def test_votes_stay_hidden_until_the_host_checks_and_the_majority_is_launched(client):
code, host = open_room(client)
state = vote(client, code, A, 0).json()
assert state["votes"] == 1 and state["mine"] == 0 and "counts" not in state and not state["host"]
vote(client, code, B, 1)
vote(client, code, C, 1)
vote(client, code, A, 1) # a voter may change their mind; still one vote
assert client.get(f"/api/science/rooms/{code}?voter={A}").json()["votes"] == 3
assert client.post(f"/api/science/rooms/{code}/check").status_code == 403 # only the host checks
state = client.post(f"/api/science/rooms/{code}/check", headers=host).json()
assert state["host"] and state["phase"] == "checked"
assert state["counts"] == [0, 3, 0, 0] and state["picked"] == 1
assert state["outcome"] == "flies" and state["right"] == 1
assert vote(client, code, B, 2).status_code == 409 # checked: closed
def test_a_wrong_majority_does_not_fly_and_names_the_answer_that_would(client):
code, host = open_room(client)
vote(client, code, A, 2)
vote(client, code, B, 2)
vote(client, code, C, 0)
state = client.post(f"/api/science/rooms/{code}/check", headers=host).json()
assert state["picked"] == 2 and state["outcome"] == "stuck" and state["right"] == 1
def test_a_tie_is_not_launched(client):
code, host = open_room(client)
assert client.post(f"/api/science/rooms/{code}/check", headers=host).status_code == 400 # no votes yet
vote(client, code, A, 0)
vote(client, code, B, 3)
state = client.post(f"/api/science/rooms/{code}/check", headers=host).json()
assert state["phase"] == "voting" and state["tie"] == [0, 3]
vote(client, code, C, 3)
state = client.post(f"/api/science/rooms/{code}/check", headers=host).json()
assert state["picked"] == 3 and state["outcome"] == "stuck" and state["tie"] == []
def test_the_host_moves_the_room_to_the_next_riddle(client):
code, host = open_room(client)
assert client.post(f"/api/science/rooms/{code}/next", headers=host).status_code == 409 # check first
vote(client, code, A, 1)
client.post(f"/api/science/rooms/{code}/check", headers=host)
state = client.post(f"/api/science/rooms/{code}/next", headers=host).json()
assert state["n"] == 2 and state["votes"] == 0 and state["phase"] == "voting"
assert vote(client, code, B, 0, n=1).status_code == 409 # a late vote for the first riddle
assert vote(client, code, B, 2, n=2).status_code == 200
client.post(f"/api/science/rooms/{code}/check", headers=host)
client.post(f"/api/science/rooms/{code}/next", headers=host)
vote(client, code, B, 1, n=3)
client.post(f"/api/science/rooms/{code}/check", headers=host)
assert client.post(f"/api/science/rooms/{code}/next", headers=host).status_code == 409 # the last riddle
def test_unknown_codes_and_choices_are_refused(client):
assert client.get("/api/science/rooms/0000").status_code == 404
assert client.post("/api/science/rooms", json={"skill": "nope"}).status_code == 404
code, _ = open_room(client)
assert vote(client, code, A, 9).status_code == 400