teecup/tests/test_individual_leaderboard.py
Erol Haagenrud dcc2a9275c Hull-for-hull-utvidelse i den autentiserte leaderboard-fanen (ADR-101)
Klikk på en spiller i slagspill/netto/Stableford-leaderboardet
ekspanderer nå raden til Ut/Inn-tabeller med hull-for-hull-score, portert
fra det tilsvarende mønsteret på den offentlige "Følg live"-siden. Nytt
lite, isolert backend-endepunkt (tournament_participant_id-nøkkede
hull), ingen migrasjon. StrokePlayLeaderboard sin LeaderboardRow-type
er uendret -- nytt valgfritt prop-sett på komponenten selv.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 05:26:46 +02:00

170 lines
7.2 KiB
Python

"""
Nøytral "ikke startet"-visning i det individuelle leaderboardet (2026-08-18):
en deltaker som ikke har spilt ett eneste hull ennå skal IKKE vises med en
falsk "E"/"0 p"-total eller en rangert plassering -- og skal, hvis runden
har et oppgitt klokkeslett/starthull, vise det i stedet. Kaller den ekte
router-funksjonen direkte (samme mønster som test_order_of_merit.py).
"""
from fastapi import HTTPException
import pytest
from app.auth import CurrentUser
from app.routers.individual_tournaments import (
HoleUpdate as TournamentHoleUpdate,
individual_leaderboard,
leaderboard_participant_round_holes,
update_hole as tournament_update_hole,
)
from tests.conftest import (
add_membership,
create_org,
create_org_hole,
create_course,
create_player,
create_tee,
create_tournament,
create_tournament_participant,
create_tournament_round,
create_tournament_round_participant,
create_user,
)
import app.db as app_db
async def _score_all_holes(tournament_id, round_id, rp_id, org_id, user_id, score):
user = CurrentUser(user_id=user_id)
for n in range(1, 19):
await tournament_update_hole(
tournament_id, round_id, rp_id, n,
TournamentHoleUpdate(gross_strokes=score, expected_version=None),
organization_id=org_id, user=user,
)
async def test_not_started_player_is_neutral_and_shows_tee_info(pool):
org_id = await create_org()
owner_id = await create_user()
await add_membership(org_id, owner_id, role="owner")
tournament_id = await create_tournament(org_id, name="Slagspill-turnering")
course_id = await create_course(org_id, name="Testbanen")
for n in range(1, 19):
await create_org_hole(org_id, course_id, hole_number=n, par=4, stroke_index=n)
tee_id = await create_tee(org_id, course_id)
async with app_db.org_connection(org_id) as conn:
await conn.execute(
"UPDATE tournament SET format_type = 'individual', scoring_method = 'stroke_gross' WHERE id = $1",
tournament_id,
)
round1_id = await create_tournament_round(org_id, tournament_id, course_id, sequence=1)
async with app_db.org_connection(org_id) as conn:
await conn.execute(
"UPDATE tournament_round SET scheduled_at = '2026-08-19 10:20:00+02', start_hole = 5 WHERE id = $1",
round1_id,
)
started_player_id = await create_player(org_id, display_name="Har startet")
started_tp_id = await create_tournament_participant(org_id, tournament_id, started_player_id)
started_rp_id = await create_tournament_round_participant(org_id, round1_id, started_tp_id, tee_id)
await _score_all_holes(tournament_id, round1_id, started_rp_id, org_id, owner_id, score=4)
not_started_player_id = await create_player(org_id, display_name="Ikke startet ennå")
not_started_tp_id = await create_tournament_participant(org_id, tournament_id, not_started_player_id)
entries = await individual_leaderboard(tournament_id, organization_id=org_id)
by_id = {e.tournament_participant_id: e for e in entries}
started = by_id[started_tp_id]
assert started.total_label == "E"
assert started.position == "1"
assert started.is_leader is True
not_started = by_id[not_started_tp_id]
assert not_started.total_label is None
assert not_started.position is None
assert not_started.is_leader is False
assert not_started.next_start_hole == 5
# ::text-castet fra Postgres kommer ut i DB-sesjonens tidssone (ikke
# nødvendigvis Europe/Oslo -- frontend gjør selve lokal-formateringen),
# så testen sjekker kun at DATOEN er riktig, ikke et eksakt klokkeslett.
assert not_started.next_tee_time is not None
assert "2026-08-19" in not_started.next_tee_time
async def test_all_not_started_has_no_leader(pool):
"""Kant-tilfelle: INGEN har spilt noe ennå -- da skal ingen markeres som
leder (alle havner i samme NO_SCORE-gruppe, som ellers ville blitt
"rank 1" og dermed feilaktig kåret til leder)."""
org_id = await create_org()
owner_id = await create_user()
await add_membership(org_id, owner_id, role="owner")
tournament_id = await create_tournament(org_id, name="Turnering uten spill ennå")
course_id = await create_course(org_id, name="Testbanen")
for n in range(1, 19):
await create_org_hole(org_id, course_id, hole_number=n, par=4, stroke_index=n)
async with app_db.org_connection(org_id) as conn:
await conn.execute(
"UPDATE tournament SET format_type = 'individual', scoring_method = 'stroke_gross' WHERE id = $1",
tournament_id,
)
round1_id = await create_tournament_round(org_id, tournament_id, course_id, sequence=1)
player_id = await create_player(org_id, display_name="Spiller")
tp_id = await create_tournament_participant(org_id, tournament_id, player_id)
entries = await individual_leaderboard(tournament_id, organization_id=org_id)
assert len(entries) == 1
assert entries[0].tournament_participant_id == tp_id
assert entries[0].total_label is None
assert entries[0].position is None
assert entries[0].is_leader is False
async def test_leaderboard_round_id_and_holes_endpoint(pool):
"""ADR-101: RoundCellOut.tournament_round_id skal peke til riktig runde,
og det nye tournament_participant_id-nøkkede hull-endepunktet (bygget for
leaderboardets hull-for-hull-utvidelse) skal returnere de samme hullene
som den eksisterende round_participant_id-nøkkede varianten -- kun
oppslagsveien er ny."""
org_id = await create_org()
owner_id = await create_user()
await add_membership(org_id, owner_id, role="owner")
tournament_id = await create_tournament(org_id, name="Hull-for-hull-turnering")
course_id = await create_course(org_id, name="Testbanen")
for n in range(1, 19):
await create_org_hole(org_id, course_id, hole_number=n, par=4, stroke_index=n)
tee_id = await create_tee(org_id, course_id)
async with app_db.org_connection(org_id) as conn:
await conn.execute(
"UPDATE tournament SET format_type = 'individual', scoring_method = 'stroke_gross' WHERE id = $1",
tournament_id,
)
round_id = await create_tournament_round(org_id, tournament_id, course_id, sequence=1)
player_id = await create_player(org_id, display_name="Spiller Ett")
tp_id = await create_tournament_participant(org_id, tournament_id, player_id)
rp_id = await create_tournament_round_participant(org_id, round_id, tp_id, tee_id)
await _score_all_holes(tournament_id, round_id, rp_id, org_id, owner_id, score=5)
entries = await individual_leaderboard(tournament_id, organization_id=org_id)
entry = next(e for e in entries if e.tournament_participant_id == tp_id)
assert len(entry.rounds) == 1
assert entry.rounds[0].tournament_round_id == round_id
holes = await leaderboard_participant_round_holes(
tournament_id, tp_id, round_id, organization_id=org_id,
)
assert len(holes) == 18
assert all(h.gross_strokes == 5 for h in holes)
with pytest.raises(HTTPException) as exc_info:
await leaderboard_participant_round_holes(
tournament_id, tp_id, "00000000-0000-0000-0000-000000000000", organization_id=org_id,
)
assert exc_info.value.status_code == 404