"""Tests for dashboard viz components and warehouse layer.""" import numpy as np import pandas as pd import pytest from dashboard.warehouse import load_players, load_fixtures, load_predictions, load_lineups, load_votes from dashboard.viz.template import register_template, FANTABETO_TEMPLATE, PITCH_GREEN, GOLD, RED, SKY from dashboard.viz.components import kpi_card, role_chip from dashboard.viz.charts import ( fixture_heatmap, percentile_radar, regression_chart, bonus_donut, card_gauge, budget_waterfall, value_scatter, error_violins, ) class TestWarehouse: def test_load_players(self): df = load_players() assert len(df) > 0 assert "player" in df.columns assert "role" in df.columns assert "fv_avg" in df.columns def test_load_fixtures(self): df = load_fixtures() assert len(df) > 0 assert "home" in df.columns assert "away" in df.columns assert "matchday" in df.columns def test_load_predictions(self): df = load_predictions() assert len(df) > 0 assert "fv_mean" in df.columns assert "starter_prob" in df.columns def test_load_lineups(self): df = load_lineups() assert len(df) > 0 assert "player" in df.columns assert "starter_pct" in df.columns def test_load_votes(self): df = load_votes() assert len(df) > 10000 assert "fantavote" in df.columns assert "matchday" in df.columns class TestTemplate: def test_registration(self): register_template() import plotly.io as pio assert FANTABETO_TEMPLATE in pio.templates def test_colors(self): assert PITCH_GREEN == "#00D084" assert GOLD == "#FFC94D" assert RED == "#FF4D5E" assert SKY == "#38BDF8" class TestComponents: def test_kpi_card(self): html = kpi_card("TEST", "42.0", "subtitle", SKY, delta=2.5) assert "TEST" in html assert "42.0" in html assert "subtitle" in html def test_role_chip(self): for role in ["P", "D", "C", "A"]: html = role_chip(role) assert role in html class TestCharts: def test_fixture_heatmap(self): df = pd.DataFrame([ {"team": "Inter", "matchday": 1, "opp_strength": 7.5}, {"team": "Inter", "matchday": 2, "opp_strength": 6.0}, {"team": "Milan", "matchday": 1, "opp_strength": 6.5}, ]) fig = fixture_heatmap(df) assert fig is not None assert len(fig.data) > 0 def test_percentile_radar(self): row = pd.Series({ "player": "Test", "goals_p90": 0.5, "assists_p90": 0.2, "xg_p90": 0.4, "progressive_passes_p90": 2.0, "tackles_p90": 1.5, "interceptions_p90": 1.0, "shots_on_target_pct": 0.4, }) metrics = ["goals_p90", "assists_p90", "xg_p90", "progressive_passes_p90", "tackles_p90", "interceptions_p90", "shots_on_target_pct"] labels = ["G", "A", "xG", "PP", "TK", "Int", "SoT"] fig = percentile_radar(row, metrics, labels) assert fig is not None def test_regression_chart(self): df = pd.DataFrame([{"goals_season": 10, "goals_p90": 0.3, "games_season": 30}]) fig = regression_chart(df, "Test", xg_col="goals_p90", goal_col="goals_season") assert fig is not None def test_bonus_donut(self): fig = bonus_donut(5, 3, 1.5) assert fig is not None def test_card_gauge(self): fig = card_gauge(0.15, 0.01) assert fig is not None def test_budget_waterfall(self): fig = budget_waterfall({"P": 30, "D": 170, "C": 160, "A": 140}) assert fig is not None def test_value_scatter(self): df = pd.DataFrame({ "player": ["A", "B", "C"], "role": ["P", "D", "C"], "fv_avg": [5.5, 6.8, 7.2], "qi": [10, 25, 30], "games_season": [35, 30, 28], }) fig = value_scatter(df) assert fig is not None def test_error_violins(self): df = pd.DataFrame({ "role": ["P"] * 10 + ["D"] * 20 + ["C"] * 30 + ["A"] * 15, "error": np.random.randn(75) * 0.5, }) fig = error_violins(df) assert fig is not None class TestPitch: def test_render_pitch(self): from dashboard.viz.pitch import render_pitch lineup = [ {"name": "GK Test", "role": "P", "fv": 6.0, "starter_pct": 95}, *[{"name": f"DEF {i}", "role": "D", "fv": 6.5, "starter_pct": 90} for i in range(4)], *[{"name": f"MID {i}", "role": "C", "fv": 7.0, "starter_pct": 85} for i in range(4)], *[{"name": f"FWD {i}", "role": "A", "fv": 8.0, "starter_pct": 90} for i in range(2)], ] svg = render_pitch(lineup, formation="4-4-2", captain="FWD 0") assert "