"""API tests for spin endpoint and wallet debit/credit.""" from __future__ import annotations import unittest from decimal import Decimal from fastapi.testclient import TestClient from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.pool import StaticPool from app.core.database import Base, get_db from app.main import create_app class SpinApiTests(unittest.TestCase): def setUp(self) -> None: engine = create_engine( "sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool, ) TestingSession = sessionmaker(bind=engine, autocommit=False, autoflush=False) Base.metadata.create_all(bind=engine) def override_get_db(): db = TestingSession() try: yield db finally: db.close() self.app = create_app() self.app.dependency_overrides[get_db] = override_get_db self.client = TestClient(self.app) self.TestingSession = TestingSession login = self.client.post( "/auth/dev-login", json={"telegram_id": 424242, "username": "tester", "first_name": "Test"}, ) self.assertEqual(login.status_code, 200) token = login.json()["access_token"] self.headers = {"Authorization": f"Bearer {token}"} agree = self.client.post("/me/agreement", headers=self.headers) self.assertEqual(agree.status_code, 200) deposit = self.client.post("/wallet/deposit", headers=self.headers, json={"amount": 1000}) self.assertEqual(deposit.status_code, 200) self.assertEqual(Decimal(deposit.json()["balance"]), Decimal("1000.00")) def test_list_games_includes_forest(self) -> None: res = self.client.get("/games") self.assertEqual(res.status_code, 200) slugs = {g["slug"]: g for g in res.json()} self.assertIn("forest-fortune", slugs) self.assertEqual(slugs["forest-fortune"]["status"], "available") self.assertEqual(slugs["forest-fortune"]["max_spin_count"], 1000) def test_spin_debit_and_credit(self) -> None: res = self.client.post( "/games/forest-fortune/spin", headers=self.headers, json={"bet": 10, "spin_count": 3}, ) self.assertEqual(res.status_code, 200, res.text) body = res.json() self.assertEqual(body["spin_count"], 3) self.assertEqual(Decimal(body["total_bet"]), Decimal("30.00")) self.assertEqual(len(body["spins"]), 3) expected = Decimal("1000.00") - Decimal(body["total_bet"]) + Decimal(body["total_win"]) self.assertEqual(Decimal(body["balance"]), expected) def test_reject_spin_count_over_limit(self) -> None: res = self.client.post( "/games/forest-fortune/spin", headers=self.headers, json={"bet": 1, "spin_count": 1001}, ) self.assertEqual(res.status_code, 422) def test_reject_spin_count_zero_via_validation(self) -> None: res = self.client.post( "/games/forest-fortune/spin", headers=self.headers, json={"bet": 1, "spin_count": 0}, ) self.assertEqual(res.status_code, 422) def test_insufficient_balance(self) -> None: res = self.client.post( "/games/forest-fortune/spin", headers=self.headers, json={"bet": 500, "spin_count": 10}, ) self.assertEqual(res.status_code, 400) self.assertIn("Insufficient", res.json()["detail"]) def test_coming_soon_unavailable(self) -> None: res = self.client.post( "/games/raven-reels/spin", headers=self.headers, json={"bet": 1, "spin_count": 1}, ) self.assertEqual(res.status_code, 503) if __name__ == "__main__": unittest.main()