Files
hockey_new/tests/test_build199_penalty_clock.py

57 lines
2.2 KiB
Python

"""Run actual penalty reconciliation with deterministic browser/physical I/O."""
from __future__ import annotations
import json
import os
from pathlib import Path
import shutil
import subprocess
import pytest
from hockey_data.service import HockeyDataService
ROOT = Path(__file__).resolve().parents[1]
SCENARIOS = tuple(
scenario
for side in ("home", "away")
for scenario in (
f"existing_{side}_two_add_four_running",
f"existing_{side}_two_add_four_paused",
f"existing_{side}_four_add_two",
f"expired_two_continues_four_{side}",
)
) + ("authoritative_missing_plate_is_restored", "strict_four_minute_shorten_then_pause", "strict_four_minute_shorten_then_resume")
def strength_fixtures() -> dict:
settings = {"strength_regulation_skaters": 5, "strength_min_skaters": 3}
result = {}
for home in range(3):
for away in range(3):
penalties = [
{"side": side, "teamPenalty": True, "infraction": {"id": "minor"},
"preset": "2", "durationMs": 120000, "remainingMs": 85000,
"running": True, "startedOnce": True, "finished": False}
for side, count in (("home", home), ("away", away)) for _ in range(count)
]
result[f"{home}:{away}"] = HockeyDataService._strength_payload(
settings, stage="regular", current_period="2",
timer_state={"penalty_board": {"penalties": penalties}}, language="ru",
)
return result
@pytest.mark.parametrize("scenario", SCENARIOS)
def test_penalty_clock_reconciliation(scenario: str) -> None:
node = shutil.which("node")
assert node, "Node is required for production-function regressions"
source = Path(os.environ.get("BUILD199_RUNTIME_SOURCE", ROOT / "ui_builder/static/app.js"))
completed = subprocess.run(
[node, str(ROOT / "tests/build199_penalty_clock.cjs"), scenario, str(source)],
input=json.dumps({"strengths": strength_fixtures()}, ensure_ascii=False),
text=True, capture_output=True, timeout=20,
)
assert completed.returncode == 0, completed.stdout + completed.stderr
assert f"PASS: {scenario}" in completed.stdout