Files
rehearshalhub/api/tests/integration/test_api_auth.py
Steffen Schuhmann f7be1b994d Initial commit: RehearsalHub POC
Full-stack self-hosted band rehearsal platform:

Backend (FastAPI + SQLAlchemy 2.0 async):
- Auth with JWT (register, login, /me, settings)
- Band management with Nextcloud folder integration
- Song management with audio version tracking
- Nextcloud scan to auto-import audio files
- Band membership with link-based invite system
- Song comments
- Audio analysis worker (BPM, key, loudness, waveform)
- Nextcloud activity watcher for auto-import
- WebSocket support for real-time annotation updates
- Alembic migrations (0001–0003)
- Repository pattern, Ruff + mypy configured

Frontend (React 18 + Vite + TypeScript strict):
- Login/register page with post-login redirect
- Home page with band list and creation form
- Band page with member panel, invite link, song list, NC scan
- Song page with waveform player, annotations, comment thread
- Settings page for per-user Nextcloud credentials
- Invite acceptance page (/invite/:token)
- ESLint v9 flat config + TypeScript strict mode

Infrastructure:
- Docker Compose: PostgreSQL, Redis, API, worker, watcher, nginx
- nginx reverse proxy for static files + /api/ proxy
- make check runs all linters before docker compose build

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 21:53:03 +01:00

74 lines
2.2 KiB
Python

"""Integration tests for auth endpoints."""
import pytest
import pytest_asyncio
@pytest.mark.asyncio
@pytest.mark.integration
async def test_register_creates_member(client, db_session):
resp = await client.post(
"/api/v1/auth/register",
json={"email": "newuser@test.com", "password": "pass123!", "display_name": "New User"},
)
assert resp.status_code == 201, resp.text
data = resp.json()
assert data["email"] == "newuser@test.com"
assert data["display_name"] == "New User"
assert "password_hash" not in data
assert "id" in data
@pytest.mark.asyncio
@pytest.mark.integration
async def test_register_duplicate_email_returns_409(client, db_session):
await client.post(
"/api/v1/auth/register",
json={"email": "dup@test.com", "password": "pass123!", "display_name": "User"},
)
resp = await client.post(
"/api/v1/auth/register",
json={"email": "dup@test.com", "password": "pass456!", "display_name": "User2"},
)
assert resp.status_code == 409
@pytest.mark.asyncio
@pytest.mark.integration
async def test_login_returns_jwt(client, db_session):
await client.post(
"/api/v1/auth/register",
json={"email": "login@test.com", "password": "pass123!", "display_name": "Login User"},
)
resp = await client.post(
"/api/v1/auth/login",
json={"email": "login@test.com", "password": "pass123!"},
)
assert resp.status_code == 200, resp.text
data = resp.json()
assert "access_token" in data
assert data["token_type"] == "bearer"
@pytest.mark.asyncio
@pytest.mark.integration
async def test_login_wrong_password_returns_401(client, db_session):
await client.post(
"/api/v1/auth/register",
json={"email": "wrongpw@test.com", "password": "correct!", "display_name": "User"},
)
resp = await client.post(
"/api/v1/auth/login",
json={"email": "wrongpw@test.com", "password": "wrong!"},
)
assert resp.status_code == 401
@pytest.mark.asyncio
@pytest.mark.integration
async def test_protected_endpoint_without_token_returns_401(client):
import uuid
resp = await client.get(f"/api/v1/bands/{uuid.uuid4()}")
assert resp.status_code == 401