feat: make scoreboard playoff-aware with banner, bracket, and series drill-down
Turn a regular-season-looking Tuesday into a full playoff experience: - Playoff banner with round + day + series + elimination counts, gold/silver Cup theme toggled by body.playoff-mode - Series context on each playoff card: round chip, series score, stake badges (GAME 7, CLINCHER, PIVOTAL), and one-line blurb - Game 7s pin to a new Spotlight section above Live - Playoff OT renders with SUDDEN DEATH badge and pulsing gold border - Client-side OT notifications via bell button in the banner - New /series/<id> drill-down with headline, next-game, and game-by-game history - New /bracket page: 7-column desktop grid, accordion on mobile - Day N banner count auto-anchors on first playoff scoreboard hit - SQLite cache for bracket + per-series schedules, stale-on-failure up to 24h Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ from app.scheduler import start_scheduler
|
||||
class TestStartScheduler:
|
||||
def test_registers_standings_refresh_every_600_seconds(self, mocker):
|
||||
mock_schedule = mocker.patch("app.scheduler.schedule")
|
||||
mocker.patch("app.scheduler.refresh_bracket")
|
||||
mocker.patch("app.scheduler.time.sleep", side_effect=StopIteration)
|
||||
|
||||
with pytest.raises(StopIteration):
|
||||
@@ -16,6 +17,7 @@ class TestStartScheduler:
|
||||
|
||||
def test_registers_score_refresh_every_10_seconds(self, mocker):
|
||||
mock_schedule = mocker.patch("app.scheduler.schedule")
|
||||
mocker.patch("app.scheduler.refresh_bracket")
|
||||
mocker.patch("app.scheduler.time.sleep", side_effect=StopIteration)
|
||||
|
||||
with pytest.raises(StopIteration):
|
||||
@@ -24,8 +26,30 @@ class TestStartScheduler:
|
||||
intervals = [call[0][0] for call in mock_schedule.every.call_args_list]
|
||||
assert 10 in intervals
|
||||
|
||||
def test_registers_bracket_refresh_every_3600_seconds(self, mocker):
|
||||
mock_schedule = mocker.patch("app.scheduler.schedule")
|
||||
mocker.patch("app.scheduler.refresh_bracket")
|
||||
mocker.patch("app.scheduler.time.sleep", side_effect=StopIteration)
|
||||
|
||||
with pytest.raises(StopIteration):
|
||||
start_scheduler()
|
||||
|
||||
intervals = [call[0][0] for call in mock_schedule.every.call_args_list]
|
||||
assert 3600 in intervals
|
||||
|
||||
def test_invokes_bracket_refresh_eagerly_at_startup(self, mocker):
|
||||
mocker.patch("app.scheduler.schedule")
|
||||
eager = mocker.patch("app.scheduler.refresh_bracket")
|
||||
mocker.patch("app.scheduler.time.sleep", side_effect=StopIteration)
|
||||
|
||||
with pytest.raises(StopIteration):
|
||||
start_scheduler()
|
||||
|
||||
assert eager.called
|
||||
|
||||
def test_runs_pending_on_each_tick(self, mocker):
|
||||
mock_schedule = mocker.patch("app.scheduler.schedule")
|
||||
mocker.patch("app.scheduler.refresh_bracket")
|
||||
call_count = {"n": 0}
|
||||
|
||||
def sleep_twice(_):
|
||||
@@ -42,6 +66,7 @@ class TestStartScheduler:
|
||||
|
||||
def test_continues_after_exception_in_run_pending(self, mocker):
|
||||
mock_schedule = mocker.patch("app.scheduler.schedule")
|
||||
mocker.patch("app.scheduler.refresh_bracket")
|
||||
call_count = {"n": 0}
|
||||
|
||||
def raise_then_stop(_):
|
||||
|
||||
Reference in New Issue
Block a user