import pytest from httpx import AsyncClient pytestmark = pytest.mark.asyncio USERS_URL = "/api/v1/users" INVITE_URL = "/api/v1/users/invite" def auth(tokens): return {"Authorization": f"Bearer {tokens['access_token']}"} async def test_list_users_as_admin(client: AsyncClient, registered_user): resp = await client.get(USERS_URL + "/", headers=auth(registered_user["tokens"])) assert resp.status_code == 200 body = resp.json() assert "total" in body assert "items" in body assert body["total"] >= 1 async def test_list_users_forbidden_for_employee(client: AsyncClient, registered_user): # Invite an employee first inv = await client.post(INVITE_URL, headers=auth(registered_user["tokens"]), json={ "email": "employee@test.de", "first_name": "Anna", "last_name": "Arbeit", "role": "EMPLOYEE", }) assert inv.status_code == 201 # Employee tries to list users – should fail # (We can't log in as employee here without accepting invite; # so we test the role check via schema validation only) assert inv.json()["role"] == "EMPLOYEE" async def test_invite_user(client: AsyncClient, registered_user): resp = await client.post(INVITE_URL, headers=auth(registered_user["tokens"]), json={ "email": "newcolleague@test.de", "first_name": "Birgit", "last_name": "Neu", "role": "MANAGER", }) assert resp.status_code == 201 body = resp.json() assert body["email"] == "newcolleague@test.de" assert body["role"] == "MANAGER" assert body["is_active"] is False # not yet accepted async def test_invite_duplicate_email(client: AsyncClient, registered_user): await client.post(INVITE_URL, headers=auth(registered_user["tokens"]), json={ "email": "dup@test.de", "first_name": "D", "last_name": "U", "role": "EMPLOYEE", }) resp = await client.post(INVITE_URL, headers=auth(registered_user["tokens"]), json={ "email": "dup@test.de", "first_name": "D", "last_name": "U", "role": "EMPLOYEE", }) assert resp.status_code == 400 async def test_get_me(client: AsyncClient, registered_user): resp = await client.get(USERS_URL + "/me", headers=auth(registered_user["tokens"])) assert resp.status_code == 200 assert resp.json()["id"] == registered_user["user"]["id"] async def test_update_user(client: AsyncClient, registered_user): user_id = registered_user["user"]["id"] resp = await client.patch( f"{USERS_URL}/{user_id}", headers=auth(registered_user["tokens"]), json={"first_name": "Maximilian"}, ) assert resp.status_code == 200 assert resp.json()["first_name"] == "Maximilian" async def test_deactivate_and_reactivate(client: AsyncClient, registered_user): # Invite a second user to deactivate inv = await client.post(INVITE_URL, headers=auth(registered_user["tokens"]), json={ "email": "temp@test.de", "first_name": "T", "last_name": "Emp", "role": "EMPLOYEE", }) user_id = inv.json()["id"] deact = await client.post( f"{USERS_URL}/{user_id}/deactivate", headers=auth(registered_user["tokens"]), ) assert deact.status_code == 200 assert deact.json()["is_active"] is False react = await client.post( f"{USERS_URL}/{user_id}/reactivate", headers=auth(registered_user["tokens"]), ) assert react.status_code == 200 assert react.json()["is_active"] is True async def test_cannot_deactivate_self(client: AsyncClient, registered_user): user_id = registered_user["user"]["id"] resp = await client.post( f"{USERS_URL}/{user_id}/deactivate", headers=auth(registered_user["tokens"]), ) assert resp.status_code == 400 async def test_set_kiosk_pin(client: AsyncClient, registered_user): user_id = registered_user["user"]["id"] resp = await client.post( f"{USERS_URL}/{user_id}/kiosk-pin", headers=auth(registered_user["tokens"]), json={"pin": "1234"}, ) assert resp.status_code == 200 async def test_kiosk_pin_must_be_numeric(client: AsyncClient, registered_user): user_id = registered_user["user"]["id"] resp = await client.post( f"{USERS_URL}/{user_id}/kiosk-pin", headers=auth(registered_user["tokens"]), json={"pin": "abcd"}, ) assert resp.status_code == 422