test(sorting): default-order regression + all-keys smoke (#68)

This commit is contained in:
2026-06-21 14:15:28 +02:00
parent 939d3a9e33
commit 4dae3a1845
4 changed files with 94 additions and 26 deletions
+64 -12
View File
@@ -82,23 +82,31 @@ def two_games(db):
class TestApplySortGames:
def test_name_ascending(self, two_games):
alpha, beta = two_games
result = apply_sort(Game.objects.all(), _find("name"), GAME_SORTS, GAME_DEFAULT_SORT)
result = apply_sort(
Game.objects.all(), _find("name"), GAME_SORTS, GAME_DEFAULT_SORT
)
assert list(result.queryset) == [alpha, beta]
assert result.terms[0].key == "name"
assert result.unknown == []
def test_name_descending(self, two_games):
alpha, beta = two_games
result = apply_sort(Game.objects.all(), _find("-name"), GAME_SORTS, GAME_DEFAULT_SORT)
result = apply_sort(
Game.objects.all(), _find("-name"), GAME_SORTS, GAME_DEFAULT_SORT
)
assert list(result.queryset) == [beta, alpha]
def test_default_sort_when_absent_is_created_desc(self, two_games):
alpha, beta = two_games # beta created after alpha
result = apply_sort(Game.objects.all(), _find(None), GAME_SORTS, GAME_DEFAULT_SORT)
result = apply_sort(
Game.objects.all(), _find(None), GAME_SORTS, GAME_DEFAULT_SORT
)
assert list(result.queryset) == [beta, alpha]
def test_unknown_key_reported_and_falls_back(self, two_games):
result = apply_sort(Game.objects.all(), _find("bogus"), GAME_SORTS, GAME_DEFAULT_SORT)
result = apply_sort(
Game.objects.all(), _find("bogus"), GAME_SORTS, GAME_DEFAULT_SORT
)
assert result.unknown == ["bogus"]
assert result.queryset.count() == 2 # still returns rows (default order)
@@ -114,13 +122,14 @@ class TestApplySortGames:
timestamp_start=datetime(2022, 1, 2, 10, tzinfo=ZONEINFO),
timestamp_end=datetime(2022, 1, 2, 11, tzinfo=ZONEINFO),
)
result = apply_sort(Game.objects.all(), _find("-playtime"), GAME_SORTS, GAME_DEFAULT_SORT)
result = apply_sort(
Game.objects.all(), _find("-playtime"), GAME_SORTS, GAME_DEFAULT_SORT
)
# two sessions on alpha must not duplicate the alpha row
assert result.queryset.count() == 2
assert list(result.queryset)[0] == alpha # most playtime first
class TestParseFindFilter:
def test_reads_sort_param(self):
request = RequestFactory().get("/x", {"sort": "-playtime,name"})
@@ -182,22 +191,30 @@ class TestListSessionsSort:
Session.objects.create(
game=alpha,
timestamp_start=datetime(2022, 1, 1, 10, tzinfo=ZONEINFO),
timestamp_end=datetime(2022, 1, 1, 13, tzinfo=ZONEINFO), # 3 h, earlier date
timestamp_end=datetime(
2022, 1, 1, 13, tzinfo=ZONEINFO
), # 3 h, earlier date
)
Session.objects.create(
game=beta,
timestamp_start=datetime(2022, 1, 2, 10, tzinfo=ZONEINFO),
timestamp_end=datetime(2022, 1, 2, 10, 30, tzinfo=ZONEINFO), # 30 min, later date
timestamp_end=datetime(
2022, 1, 2, 10, 30, tzinfo=ZONEINFO
), # 30 min, later date
)
# default order is -date (beta first); -duration must override it (alpha's 3h first)
response = logged_client.get(reverse("games:list_sessions"), {"sort": "-duration"})
response = logged_client.get(
reverse("games:list_sessions"), {"sort": "-duration"}
)
assert response.status_code == 200
body = response.content.decode()
# Extract only the table body to avoid finding "Beta" in header's last-session button
tbody_match = re.search(r"<tbody[^>]*>(.*?)</tbody>", body, re.DOTALL)
assert tbody_match
tbody = tbody_match.group(1)
assert tbody.index("Alpha") < tbody.index("Beta") # longer session first, despite earlier date
assert tbody.index("Alpha") < tbody.index(
"Beta"
) # longer session first, despite earlier date
def test_unknown_sort_emits_warning(self, logged_client, two_games):
response = logged_client.get(reverse("games:list_sessions"), {"sort": "nope"})
@@ -229,7 +246,9 @@ class TestListPurchasesSort:
def test_sort_by_price_descending(self, logged_client, two_purchases):
# default -purchased puts Alpha (later date) first; -price must override to show Beta (90) first
response = logged_client.get(reverse("games:list_purchases"), {"sort": "-price"})
response = logged_client.get(
reverse("games:list_purchases"), {"sort": "-price"}
)
assert response.status_code == 200
body = response.content.decode()
tbody = re.search(r"<tbody[^>]*>(.*?)</tbody>", body, re.DOTALL).group(1)
@@ -238,7 +257,9 @@ class TestListPurchasesSort:
def test_name_aggregate_sort_no_duplicate_rows(self, logged_client, two_purchases):
# a multi-game purchase must still render exactly one row
cheap, _ = two_purchases
extra = Game.objects.create(name="Aaa", sort_name="Aaa", platform=cheap.platform)
extra = Game.objects.create(
name="Aaa", sort_name="Aaa", platform=cheap.platform
)
cheap.games.add(extra)
response = logged_client.get(reverse("games:list_purchases"), {"sort": "name"})
body = response.content.decode()
@@ -248,3 +269,34 @@ class TestListPurchasesSort:
response = logged_client.get(reverse("games:list_purchases"), {"sort": "nope"})
warnings = [str(m) for m in get_messages(response.wsgi_request)]
assert any("nope" in w for w in warnings)
class TestDefaultOrderUnchanged:
"""The default sort strings must reproduce the pre-#68 hardcoded order."""
def test_games_default_is_created_descending(self, logged_client, two_games):
alpha, beta = two_games # beta newer
response = logged_client.get(reverse("games:list_games"))
body = response.content.decode()
tbody_match = re.search(r"<tbody[^>]*>(.*?)</tbody>", body, re.DOTALL)
assert tbody_match
tbody = tbody_match.group(1)
assert tbody.index("Beta") < tbody.index("Alpha")
class TestEverySortKeyReturns200:
def test_all_game_keys(self, logged_client, two_games):
for key in GAME_SORTS:
for raw in (key, f"-{key}"):
response = logged_client.get(reverse("games:list_games"), {"sort": raw})
assert response.status_code == 200, raw
def test_all_session_keys(self, logged_client, two_games):
for key in SESSION_SORTS:
response = logged_client.get(reverse("games:list_sessions"), {"sort": key})
assert response.status_code == 200, key
def test_all_purchase_keys(self, logged_client, two_games):
for key in PURCHASE_SORTS:
response = logged_client.get(reverse("games:list_purchases"), {"sort": key})
assert response.status_code == 200, key