"""Player-specific evaluation views (the "By player" toggle and its page). These pages regroup the flat evaluation table by player: one row per player in the table view, and a dedicated page per player with left/right navigation and per-criterion averages. Visibility follows the viewer's role — managers and coaches see staff-authored evaluations inside their own tryouts. """ from datetime import date import pytest from app.extensions import db from app.models import Evaluation, Tryout @pytest.fixture def staff_setup(app, as_role, make_user): """A coach who manages one tryout, plus staff, a player, and a foreign tryout.""" coach_id = as_role('coach', username='viewer_coach') manager_id = make_user('manager', username='other_manager') admin_id = make_user('admin', username='the_admin') player_id = make_user('player', username='the_player') outsider_id = make_user('coach', username='outsider_coach') with app.app_context(): tryout = Tryout( title='Spring', game='Valorant', date=date(2030, 4, 1), created_by=coach_id, coach_id=coach_id, ) db.session.add(tryout) db.session.flush() other_tryout = Tryout( title='Other', game='Valorant', date=date(2030, 5, 1), created_by=outsider_id, ) db.session.add(other_tryout) db.session.commit() return { 'coach_id': coach_id, 'manager_id': manager_id, 'admin_id': admin_id, 'player_id': player_id, 'tryout_id': tryout.id, 'other_tryout_id': other_tryout.id, } class TestVisibility: def test_coach_sees_staff_evaluations_only_in_their_tryout(self, app, client, staff_setup): with app.app_context(): db.session.add( Evaluation( tryout_id=staff_setup['tryout_id'], player_id=staff_setup['player_id'], evaluator_id=staff_setup['manager_id'], overall_score=7, comments='manager in own tryout', ) ) db.session.add( Evaluation( tryout_id=staff_setup['tryout_id'], player_id=staff_setup['player_id'], evaluator_id=staff_setup['admin_id'], overall_score=5, comments='admin authored', ) ) db.session.add( Evaluation( tryout_id=staff_setup['other_tryout_id'], player_id=staff_setup['player_id'], evaluator_id=staff_setup['manager_id'], overall_score=9, comments='manager other tryout', ) ) db.session.commit() body = client.get(f"/evaluations/player/{staff_setup['player_id']}").get_data(as_text=True) assert 'manager in own tryout' in body assert 'admin authored' not in body assert 'manager other tryout' not in body def test_admin_sees_every_evaluation(self, app, client, as_role, make_user): admin_id = as_role('admin', username='boss') coach_id = make_user('coach', username='some_coach') player_id = make_user('player', username='star') with app.app_context(): tryout = Tryout( title='T', game='Valorant', date=date(2030, 1, 1), created_by=admin_id, ) db.session.add(tryout) db.session.flush() db.session.add( Evaluation( tryout_id=tryout.id, player_id=player_id, evaluator_id=coach_id, overall_score=6, comments='coach comment', ) ) db.session.add( Evaluation( tryout_id=tryout.id, player_id=player_id, evaluator_id=admin_id, overall_score=4, comments='admin comment', ) ) db.session.commit() body = client.get(f'/evaluations/player/{player_id}').get_data(as_text=True) assert 'coach comment' in body assert 'admin comment' in body def test_a_player_cannot_open_the_player_page(self, client, as_role): player_id = as_role('player') response = client.get(f'/evaluations/player/{player_id}', follow_redirects=False) assert response.status_code in (301, 302) class TestAggregates: def test_combined_and_per_criterion_averages(self, app, client, as_role, make_user): coach_id = as_role('coach', username='agg_coach') coach2_id = make_user('coach', username='agg_coach2') player_id = make_user('player', username='agg_player') with app.app_context(): tryout = Tryout( title='Agg', game='Valorant', date=date(2030, 1, 1), created_by=coach_id, coach_id=coach_id, ) db.session.add(tryout) db.session.flush() first = Evaluation(tryout_id=tryout.id, player_id=player_id, evaluator_id=coach_id) first.apply_scores({'mecanics_score': 8, 'mental_score': 6}) second = Evaluation(tryout_id=tryout.id, player_id=player_id, evaluator_id=coach2_id) second.apply_scores({'mecanics_score': 4, 'mental_score': 8}) db.session.add_all([first, second]) db.session.commit() body = client.get(f'/evaluations/player/{player_id}').get_data(as_text=True) # overall: (7 + 6) / 2 = 6.5; mecanics: 6.0; mental: 7.0. assert '6.5' in body assert '6.0' in body assert '7.0' in body class TestNavigation: def test_players_are_ordered_best_first_with_arrows(self, app, client, as_role, make_user): coach_id = as_role('coach', username='order_coach') high = make_user('player', username='zzz_high') mid = make_user('player', username='aaa_mid') low = make_user('player', username='mmm_low') with app.app_context(): tryout = Tryout( title='Order', game='Valorant', date=date(2030, 1, 1), created_by=coach_id, coach_id=coach_id, ) db.session.add(tryout) db.session.flush() for player_id, score in [(high, 8), (mid, 5), (low, 3)]: db.session.add( Evaluation( tryout_id=tryout.id, player_id=player_id, evaluator_id=coach_id, overall_score=score, ) ) db.session.commit() best = client.get(f'/evaluations/player/{high}').get_data(as_text=True) middle = client.get(f'/evaluations/player/{mid}').get_data(as_text=True) worst = client.get(f'/evaluations/player/{low}').get_data(as_text=True) # Best: no previous (left arrow disabled), next is the middle player. assert 'aria-disabled="true"' in best assert f'/evaluations/player/{mid}' in best assert f'/evaluations/player/{low}' not in best # Middle: both arrows active, pointing at the neighbours. assert f'/evaluations/player/{high}' in middle assert f'/evaluations/player/{low}' in middle assert 'aria-disabled="true"' not in middle # Worst: no next (right arrow disabled), previous is the middle player. assert 'aria-disabled="true"' in worst assert f'/evaluations/player/{mid}' in worst assert f'/evaluations/player/{high}' not in worst class TestTableView: def test_table_groups_by_player_and_keeps_the_comment(self, app, client, as_role, make_user): coach_id = as_role('coach', username='table_coach') player_id = make_user('player', username='table_player') with app.app_context(): tryout = Tryout( title='T', game='Valorant', date=date(2030, 1, 1), created_by=coach_id, coach_id=coach_id, ) db.session.add(tryout) db.session.flush() db.session.add( Evaluation( tryout_id=tryout.id, player_id=player_id, evaluator_id=coach_id, overall_score=7, comments='a distinctive comment', ) ) db.session.commit() body = client.get('/evaluations').get_data(as_text=True) assert 'table_player' in body assert f'/evaluations/player/{player_id}' in body assert 'a distinctive comment' in body