Testing
The project ships a pytest suite under tests/ covering the V1 and V2 APIs, auth flows, models, security helpers, the bot platform, and the video integration.
Quick start
# in the project venv
.venv/bin/python -m pytest tests/ -q
Run a single file:
.venv/bin/python -m pytest tests/test_spav2_messages.py -v
Run only V2 tests:
.venv/bin/python -m pytest tests/ -k spav2
Test harness (tests/conftest.py)
appfixture (session scope) — application factory (create_app()) with an in-memory SQLite DB (sqlite:///:memory:), plusTESTING=True,MAIL_SUPPRESS_SEND=True,WTF_CSRF_ENABLED=False.clientfixture (function scope) —app.test_client()per test.sessionfixture (function scope) — truncates all tables (_clear_all_tables()) so tests are isolated.- Ready-made users:
user,user2,user3,admin_user,premium_user; ready-made chat:personal_chat. - Logged-in clients:
logged_in_client,logged_in_admin,logged_in_premium,logged_in_user2(session-based), pluslogin_as(client, user)helper. clear_rate_limiter(autouse) — resets the in-memory rate limiter before each test.
Layout of tests/
| File | Covers |
|---|---|
test_auth.py |
register/login/logout, check_username, verify email, sessions |
test_api_spa.py |
V1 /api JSON helpers (chat list, send, messages) |
test_bot_api.py |
Bot platform: list, send, webapps, webhook routing |
test_chats.py |
Chat list/history, typing, read receipts |
test_client_api.py |
Client-facing V2 API basics, error format |
test_files.py |
Upload/download, file metadata, size limits |
test_helpers.py, test_helpers_ext.py |
message_to_dict, get_current_user_id, emoji validation, models helpers |
test_models.py, test_models_ext.py |
Core models + relationships + extended model coverage |
test_security.py |
Headers, CSRF, rate limiter, crypto round-trip |
test_performance.py |
Sanity benchmarks for hot paths (chat list, message send) |
test_spa_groups_channels.py |
V1 groups & channels HTML/JSON views |
test_spa_messages_stories.py |
V1 messages + stories |
test_spa_profile_calls.py |
V1 profile & calls |
test_spav2_auth.py |
V2 auth: check_username, register, login, logout |
test_spav2_login_v3.py |
V2 OTP / password / preloaded-avatar login flows |
test_spav2_messages.py |
V2 send/edit/delete, emojis, reactions, replies, schedule |
test_spav2_chat.py |
V2 chat list, per-user messages, typing |
test_spav2_contacts.py |
V2 contacts, block/unblock |
test_spav2_groups.py |
V2 groups, roles, invites, join/leave |
test_spav2_channels.py |
V2 channels, subscribe, admins |
test_spav2_stories.py |
V2 stories create/view/like/react/stats |
test_spav2_search.py |
V2 search endpoints |
test_spav2_sessions.py |
V2 session list/revoke |
test_spav2_profile.py |
V2 profile update/avatar/privacy |
test_spav2_saved.py |
V2 saved messages & notes |
test_spav2_music.py |
V2 music library |
test_spav2_ksettings.py |
V2 key settings |
test_spav2_oauth.py |
V2 Google OAuth flow |
test_spav2_qr_login.py |
V2 QR-login flow |
test_spav2_push.py |
V2 Web Push subscribe/unsubscribe |
test_spav2_calls.py |
V2 call history/make |
test_spav2_admin.py |
Admin panel endpoints & authorization gates |
test_spav2_bot_webhook.py |
Bot webhook ingest |
test_video_integration.py |
/video/integration/* room lifecycle |
test_utils_api.py |
/health, /stats, /endpoints, get_user_id |
File list verified against the repo at v4.0.0 — run
python -m pytest --collect-only tests/for the authoritative list on newer checkouts.
Writing tests
Follow existing patterns in test_spav2_*.py. The suite authenticates via Flask sessions (login_as, logged_in_client), not Bearer headers:
from tests.conftest import login_as, personal_chat, user, user2
def test_send_message(client, personal_chat, user):
login_as(client, user)
r = client.post("/api.v2/api/send_message",
json={"chat_id": personal_chat.id, "text": "hi"})
assert r.status_code == 200
assert r.get_json()["success"] is True
Guidelines:
- Use the
clientfixture; never share state between tests (tables are cleared). - Register fresh users per test (usernames must be unique).
- Assert both status codes and
success/data/errorshapes. - For auth-gated routes, assert
401/403when no/invalid token is sent. - For security-sensitive behavior (rate limits, CSRF), keep tests independent of shared counters.
CI integration
No CI config is committed; a typical GitHub Actions workflow:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install -r requirements.txt pytest
- run: python -m pytest tests/ -q
Coverage
Optional coverage report:
.venv/bin/python -m pytest tests/ -q --cov=app --cov-report=term-missing
See Getting Started for env setup and Deployment for running the same suite in a container.