chore: reorganize test files into domain-specific subdirectories under tests/
Split the monolithic test directory into three tiers (unit, api, e2e) with a path-mirroring directory structure. Added corresponding Makefile targets (test-unit, test-api, test-e2e) and updated all documentation references (CLAUDE.md, README.md, testing-cicd.html, testing-framework.html, testing-make.html) to reflect the new layout and naming conventions.
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
import time
|
||||
import requests
|
||||
from tests.conftest import BASE_URL
|
||||
from devplacepy.database import get_table
|
||||
_counter_polls = [0]
|
||||
AJAX_polls = {"X-Requested-With": "fetch"}
|
||||
def _session_polls():
|
||||
_counter_polls[0] += 1
|
||||
name = f"pol{int(time.time() * 1000)}{_counter_polls[0]}"
|
||||
s = requests.Session()
|
||||
s.post(
|
||||
f"{BASE_URL}/auth/signup",
|
||||
data={
|
||||
"username": name,
|
||||
"email": f"{name}@t.dev",
|
||||
"password": "secret123",
|
||||
"confirm_password": "secret123",
|
||||
},
|
||||
allow_redirects=True,
|
||||
)
|
||||
return s, name
|
||||
def _create_post_polls(session, title, question, options):
|
||||
fields = [
|
||||
("content", "Poll host post content for tests."),
|
||||
("title", title),
|
||||
("topic", "question"),
|
||||
("poll_question", question),
|
||||
]
|
||||
fields.extend(("poll_options", option) for option in options)
|
||||
r = session.post(f"{BASE_URL}/posts/create", data=fields, allow_redirects=False)
|
||||
slug = r.headers["location"].split("/posts/")[-1]
|
||||
return get_table("posts").find_one(slug=slug)["uid"]
|
||||
def _poll_for(post_uid):
|
||||
poll = get_table("polls").find_one(post_uid=post_uid)
|
||||
options = list(
|
||||
get_table("poll_options").find(poll_uid=poll["uid"], order_by=["position"])
|
||||
)
|
||||
return poll, options
|
||||
def _create_plain_post_polls(session, title):
|
||||
r = session.post(
|
||||
f"{BASE_URL}/posts/create",
|
||||
data={
|
||||
"content": "Plain post awaiting a poll on edit.",
|
||||
"title": title,
|
||||
"topic": "question",
|
||||
},
|
||||
allow_redirects=False,
|
||||
)
|
||||
slug = r.headers["location"].split("/posts/")[-1]
|
||||
return slug, get_table("posts").find_one(slug=slug)["uid"]
|
||||
|
||||
|
||||
def test_valid_poll_persists(app_server):
|
||||
s, _ = _session_polls()
|
||||
title = f"valid-poll-{int(time.time() * 1000)}"
|
||||
post_uid = _create_post_polls(s, title, "Tabs or spaces?", ["Tabs", "Spaces", "Both"])
|
||||
poll, options = _poll_for(post_uid)
|
||||
assert poll is not None
|
||||
assert len(options) == 3
|
||||
|
||||
|
||||
def test_poll_dropped_with_one_option(app_server):
|
||||
s, _ = _session_polls()
|
||||
title = f"one-option-{int(time.time() * 1000)}"
|
||||
post_uid = _create_post_polls(s, title, "Only one?", ["Solo"])
|
||||
assert get_table("polls").find_one(post_uid=post_uid) is None
|
||||
|
||||
|
||||
def test_poll_dropped_without_question(app_server):
|
||||
s, _ = _session_polls()
|
||||
title = f"no-question-{int(time.time() * 1000)}"
|
||||
post_uid = _create_post_polls(s, title, "", ["Tabs", "Spaces"])
|
||||
assert get_table("polls").find_one(post_uid=post_uid) is None
|
||||
|
||||
|
||||
def test_vote_records_choice(app_server):
|
||||
s, _ = _session_polls()
|
||||
title = f"vote-{int(time.time() * 1000)}"
|
||||
post_uid = _create_post_polls(s, title, "Pick one", ["A", "B"])
|
||||
poll, options = _poll_for(post_uid)
|
||||
r = s.post(
|
||||
f"{BASE_URL}/polls/{poll['uid']}/vote",
|
||||
data={"option_uid": options[0]["uid"]},
|
||||
headers=AJAX_polls,
|
||||
)
|
||||
payload = r.json()
|
||||
assert payload["total"] == 1
|
||||
assert payload["my_choice"] == options[0]["uid"]
|
||||
assert get_table("poll_votes").count(poll_uid=poll["uid"]) == 1
|
||||
|
||||
|
||||
def test_switch_vote_moves_choice(app_server):
|
||||
s, _ = _session_polls()
|
||||
title = f"switch-{int(time.time() * 1000)}"
|
||||
post_uid = _create_post_polls(s, title, "Pick one", ["A", "B"])
|
||||
poll, options = _poll_for(post_uid)
|
||||
s.post(
|
||||
f"{BASE_URL}/polls/{poll['uid']}/vote",
|
||||
data={"option_uid": options[0]["uid"]},
|
||||
headers=AJAX_polls,
|
||||
)
|
||||
r = s.post(
|
||||
f"{BASE_URL}/polls/{poll['uid']}/vote",
|
||||
data={"option_uid": options[1]["uid"]},
|
||||
headers=AJAX_polls,
|
||||
)
|
||||
payload = r.json()
|
||||
assert payload["my_choice"] == options[1]["uid"]
|
||||
assert payload["total"] == 1
|
||||
|
||||
|
||||
def test_repeat_same_option_retracts(app_server):
|
||||
s, _ = _session_polls()
|
||||
title = f"retract-{int(time.time() * 1000)}"
|
||||
post_uid = _create_post_polls(s, title, "Pick one", ["A", "B"])
|
||||
poll, options = _poll_for(post_uid)
|
||||
s.post(
|
||||
f"{BASE_URL}/polls/{poll['uid']}/vote",
|
||||
data={"option_uid": options[0]["uid"]},
|
||||
headers=AJAX_polls,
|
||||
)
|
||||
r = s.post(
|
||||
f"{BASE_URL}/polls/{poll['uid']}/vote",
|
||||
data={"option_uid": options[0]["uid"]},
|
||||
headers=AJAX_polls,
|
||||
)
|
||||
payload = r.json()
|
||||
assert payload["my_choice"] is None
|
||||
assert payload["total"] == 0
|
||||
assert get_table("poll_votes").count(poll_uid=poll["uid"], deleted_at=None) == 0
|
||||
|
||||
|
||||
def test_vote_invalid_option_returns_400(app_server):
|
||||
s, _ = _session_polls()
|
||||
title = f"badopt-{int(time.time() * 1000)}"
|
||||
post_uid = _create_post_polls(s, title, "Pick one", ["A", "B"])
|
||||
poll, _ = _poll_for(post_uid)
|
||||
r = s.post(
|
||||
f"{BASE_URL}/polls/{poll['uid']}/vote",
|
||||
data={"option_uid": "not-a-real-option"},
|
||||
headers=AJAX_polls,
|
||||
)
|
||||
assert r.status_code == 400
|
||||
|
||||
|
||||
def test_vote_requires_login(app_server):
|
||||
s, _ = _session_polls()
|
||||
title = f"authvote-{int(time.time() * 1000)}"
|
||||
post_uid = _create_post_polls(s, title, "Pick one", ["A", "B"])
|
||||
poll, options = _poll_for(post_uid)
|
||||
anon = requests.Session()
|
||||
r = anon.post(
|
||||
f"{BASE_URL}/polls/{poll['uid']}/vote",
|
||||
data={"option_uid": options[0]["uid"]},
|
||||
headers=AJAX_polls,
|
||||
allow_redirects=False,
|
||||
)
|
||||
assert r.status_code == 303
|
||||
assert get_table("poll_votes").count(poll_uid=poll["uid"]) == 0
|
||||
|
||||
|
||||
def test_multi_field_options_keep_embedded_commas(app_server):
|
||||
s, _ = _session_polls()
|
||||
title = f"comma-label-{int(time.time() * 1000)}"
|
||||
post_uid = _create_post_polls(s, title, "Sure?", ["Yes, definitely", "No, never"])
|
||||
_, options = _poll_for(post_uid)
|
||||
assert [option["label"] for option in options] == ["Yes, definitely", "No, never"]
|
||||
Reference in New Issue
Block a user