114 lines
3.9 KiB
Python
114 lines
3.9 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from fastapi.testclient import TestClient
|
||
|
|
|
||
|
|
from tests.conftest import create_onboarded_student
|
||
|
|
|
||
|
|
|
||
|
|
def test_zero_to_forty_question_limit_and_mixed_grading(client: TestClient) -> None:
|
||
|
|
token_a, _ = create_onboarded_student(client, "author_owl", "owl", "avatar-2")
|
||
|
|
headers_a = {"Authorization": f"Bearer {token_a}"}
|
||
|
|
|
||
|
|
# 0 questions is valid on free tier
|
||
|
|
zero_resp = client.post(
|
||
|
|
"/api/v1/quizzes",
|
||
|
|
headers=headers_a,
|
||
|
|
json={
|
||
|
|
"title": "Draft Empty Quiz",
|
||
|
|
"description": "Zero questions allowed",
|
||
|
|
"is_public": True,
|
||
|
|
"questions": [],
|
||
|
|
},
|
||
|
|
)
|
||
|
|
assert zero_resp.status_code == 201
|
||
|
|
assert zero_resp.json()["question_count"] == 0
|
||
|
|
assert zero_resp.json()["quiz_mode"] == "empty"
|
||
|
|
|
||
|
|
# 41 questions is rejected on free tier
|
||
|
|
too_many = [
|
||
|
|
{
|
||
|
|
"question_type": "write_in",
|
||
|
|
"prompt": f"Question {i}",
|
||
|
|
"correct_answer": str(i),
|
||
|
|
}
|
||
|
|
for i in range(41)
|
||
|
|
]
|
||
|
|
over_limit = client.post(
|
||
|
|
"/api/v1/quizzes",
|
||
|
|
headers=headers_a,
|
||
|
|
json={"title": "41 Questions", "is_public": True, "questions": too_many},
|
||
|
|
)
|
||
|
|
assert over_limit.status_code == 422
|
||
|
|
|
||
|
|
# Create mixed Multiple-Choice + Write-In quiz
|
||
|
|
quiz_resp = client.post(
|
||
|
|
"/api/v1/quizzes",
|
||
|
|
headers=headers_a,
|
||
|
|
json={
|
||
|
|
"title": "Science Sprint",
|
||
|
|
"description": "Test MC and write-in",
|
||
|
|
"is_public": True,
|
||
|
|
"questions": [
|
||
|
|
{
|
||
|
|
"question_type": "multiple_choice",
|
||
|
|
"prompt": "What is H2O?",
|
||
|
|
"options": [
|
||
|
|
{"id": "a", "text": "Water"},
|
||
|
|
{"id": "b", "text": "Helium"},
|
||
|
|
],
|
||
|
|
"correct_answer": "a",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"question_type": "write_in",
|
||
|
|
"prompt": "How many planets orbit the Sun?",
|
||
|
|
"correct_answer": "8",
|
||
|
|
"accepted_answers": ["eight"],
|
||
|
|
},
|
||
|
|
],
|
||
|
|
},
|
||
|
|
)
|
||
|
|
assert quiz_resp.status_code == 201
|
||
|
|
quiz = quiz_resp.json()
|
||
|
|
quiz_id = quiz["id"]
|
||
|
|
share_slug = quiz["share_slug"]
|
||
|
|
q1_id = str(quiz["questions"][0]["id"])
|
||
|
|
q2_id = str(quiz["questions"][1]["id"])
|
||
|
|
|
||
|
|
# Fetch via share_slug as unauthenticated visitor (clear session cookie first)
|
||
|
|
client.cookies.clear()
|
||
|
|
by_slug = client.get(f"/api/v1/quizzes/{share_slug}")
|
||
|
|
assert by_slug.status_code == 200
|
||
|
|
assert by_slug.json()["editable_questions"] is None
|
||
|
|
|
||
|
|
# Player B plays twice: first 100%, then 50% -> latest is 50%, all-time best stays 100%!
|
||
|
|
token_b, _ = create_onboarded_student(client, "speedy_otter", "otter", "avatar-4")
|
||
|
|
headers_b = {"Authorization": f"Bearer {token_b}"}
|
||
|
|
|
||
|
|
sub1 = client.post(
|
||
|
|
f"/api/v1/quizzes/{quiz_id}/submit",
|
||
|
|
headers=headers_b,
|
||
|
|
json={"answers": {q1_id: "a", q2_id: " EIGHT "}},
|
||
|
|
)
|
||
|
|
assert sub1.status_code == 200
|
||
|
|
assert sub1.json()["score_percent"] == 100.0
|
||
|
|
|
||
|
|
sub2 = client.post(
|
||
|
|
f"/api/v1/quizzes/{quiz_id}/submit",
|
||
|
|
headers=headers_b,
|
||
|
|
json={"answers": {q1_id: "a", q2_id: "nine"}},
|
||
|
|
)
|
||
|
|
assert sub2.status_code == 200
|
||
|
|
s2 = sub2.json()
|
||
|
|
assert s2["my_latest_score"]["score_percent"] == 50.0
|
||
|
|
assert s2["my_best_score"]["score_percent"] == 100.0
|
||
|
|
assert s2["global_best_score"]["score_percent"] == 100.0
|
||
|
|
assert s2["global_best_score"]["holder_nickname"] == "speedy_otter"
|
||
|
|
|
||
|
|
# Thumbs up and down voting
|
||
|
|
v_up = client.post(f"/api/v1/quizzes/{quiz_id}/vote", headers=headers_a, json={"value": 1})
|
||
|
|
assert v_up.status_code == 200
|
||
|
|
v_down = client.post(f"/api/v1/quizzes/{quiz_id}/vote", headers=headers_b, json={"value": -1})
|
||
|
|
assert v_down.status_code == 200
|
||
|
|
assert v_down.json()["upvotes"] == 1
|
||
|
|
assert v_down.json()["downvotes"] == 1
|