Initial commit – TimeMaster Zeiterfassung & HR-Tool
Stand: agent-06 (Audit-Log), agent-05 (Krankmeldung), agent-07 Phase 1 (Personalnummer), Busylight-Pull-Integration, TOTP/2FA, Abwesenheiten, Zeiterfassung, Kiosk-Grundgerüst. Migrations 0001–0023 deployed auf 192.168.1.137 + .164. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
import pytest
|
||||
from httpx import AsyncClient
|
||||
|
||||
pytestmark = pytest.mark.asyncio
|
||||
|
||||
REGISTER_URL = "/api/v1/auth/register"
|
||||
LOGIN_URL = "/api/v1/auth/login"
|
||||
REFRESH_URL = "/api/v1/auth/refresh"
|
||||
LOGOUT_URL = "/api/v1/auth/logout"
|
||||
RESET_URL = "/api/v1/auth/password-reset"
|
||||
ME_URL = "/api/v1/auth/me"
|
||||
|
||||
|
||||
async def test_register_success(client: AsyncClient):
|
||||
resp = await client.post(REGISTER_URL, json={
|
||||
"company_name": "Acme GmbH",
|
||||
"first_name": "Erika",
|
||||
"last_name": "Muster",
|
||||
"email": "erika@acme.de",
|
||||
"password": "Secure123",
|
||||
})
|
||||
assert resp.status_code == 201
|
||||
body = resp.json()
|
||||
assert "access_token" in body
|
||||
assert "refresh_token" in body
|
||||
assert body["token_type"] == "bearer"
|
||||
|
||||
|
||||
async def test_register_duplicate_email(client: AsyncClient, registered_user):
|
||||
resp = await client.post(REGISTER_URL, json={
|
||||
"company_name": "Other GmbH",
|
||||
"first_name": "Max",
|
||||
"last_name": "Mustermann",
|
||||
"email": registered_user["user"]["email"],
|
||||
"password": "Secret123",
|
||||
})
|
||||
assert resp.status_code == 400
|
||||
assert "already registered" in resp.json()["detail"]
|
||||
|
||||
|
||||
async def test_register_weak_password(client: AsyncClient):
|
||||
resp = await client.post(REGISTER_URL, json={
|
||||
"company_name": "Weak Corp",
|
||||
"first_name": "A",
|
||||
"last_name": "B",
|
||||
"email": "weak@corp.de",
|
||||
"password": "nouppercase1",
|
||||
})
|
||||
assert resp.status_code == 422
|
||||
|
||||
|
||||
async def test_login_success(client: AsyncClient, registered_user):
|
||||
resp = await client.post(LOGIN_URL, json={
|
||||
"email": registered_user["user"]["email"],
|
||||
"password": "Secret123",
|
||||
})
|
||||
assert resp.status_code == 200
|
||||
assert "access_token" in resp.json()
|
||||
|
||||
|
||||
async def test_login_wrong_password(client: AsyncClient, registered_user):
|
||||
resp = await client.post(LOGIN_URL, json={
|
||||
"email": registered_user["user"]["email"],
|
||||
"password": "WrongPassword1",
|
||||
})
|
||||
assert resp.status_code == 401
|
||||
|
||||
|
||||
async def test_login_unknown_email(client: AsyncClient):
|
||||
resp = await client.post(LOGIN_URL, json={
|
||||
"email": "nobody@nowhere.de",
|
||||
"password": "Secret123",
|
||||
})
|
||||
assert resp.status_code == 401
|
||||
|
||||
|
||||
async def test_me_authenticated(client: AsyncClient, registered_user):
|
||||
resp = await client.get(
|
||||
ME_URL,
|
||||
headers={"Authorization": f"Bearer {registered_user['tokens']['access_token']}"},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
body = resp.json()
|
||||
assert body["email"] == registered_user["user"]["email"]
|
||||
assert body["role"] == "COMPANY_ADMIN"
|
||||
|
||||
|
||||
async def test_me_unauthenticated(client: AsyncClient):
|
||||
resp = await client.get(ME_URL)
|
||||
assert resp.status_code == 401
|
||||
|
||||
|
||||
async def test_token_refresh(client: AsyncClient, registered_user):
|
||||
resp = await client.post(REFRESH_URL, json={
|
||||
"refresh_token": registered_user["tokens"]["refresh_token"],
|
||||
})
|
||||
assert resp.status_code == 200
|
||||
new_tokens = resp.json()
|
||||
assert "access_token" in new_tokens
|
||||
# Old refresh token should now be invalid (rotation)
|
||||
resp2 = await client.post(REFRESH_URL, json={
|
||||
"refresh_token": registered_user["tokens"]["refresh_token"],
|
||||
})
|
||||
assert resp2.status_code == 401
|
||||
|
||||
|
||||
async def test_logout(client: AsyncClient):
|
||||
reg = await client.post(REGISTER_URL, json={
|
||||
"company_name": "Logout Corp",
|
||||
"first_name": "Hans",
|
||||
"last_name": "Logout",
|
||||
"email": "hans@logout.de",
|
||||
"password": "Secret123",
|
||||
})
|
||||
tokens = reg.json()
|
||||
resp = await client.post(LOGOUT_URL, json={"refresh_token": tokens["refresh_token"]})
|
||||
assert resp.status_code == 200
|
||||
# Refresh should now fail
|
||||
resp2 = await client.post(REFRESH_URL, json={"refresh_token": tokens["refresh_token"]})
|
||||
assert resp2.status_code == 401
|
||||
|
||||
|
||||
async def test_password_reset_request(client: AsyncClient, registered_user):
|
||||
resp = await client.post(RESET_URL, json={"email": registered_user["user"]["email"]})
|
||||
assert resp.status_code == 200
|
||||
# Same response for unknown email (anti-enumeration)
|
||||
resp2 = await client.post(RESET_URL, json={"email": "nobody@x.de"})
|
||||
assert resp2.status_code == 200
|
||||
Reference in New Issue
Block a user