import unittest from fastapi.testclient import TestClient import main from db import connect, create class TestInvitationsV2(unittest.IsolatedAsyncioTestCase): async def asyncSetUp(self): self.conn = await connect(":memory:") await create(self.conn) async def override_get_db(): try: yield self.conn finally: pass main.app.dependency_overrides[main.get_db] = override_get_db self.client = TestClient(main.app) # Register inviter r = self.client.post( "/api/v1/auth/register", json={"email": "owner@test.com", "password": "pw", "displayName": "Owner"}, ) assert r.status_code == 200, r.text self.owner_headers = {"Authorization": f"Bearer {r.json()['accessToken']}"} # Create household r = self.client.post( "/api/v1/households", headers=self.owner_headers, json={"name": "Team"} ) assert r.status_code == 200, r.text self.slug = r.json()["slug"] async def asyncTearDown(self): await self.conn.close() main.app.dependency_overrides.clear() def test_create_invitation_and_accept(self): # Create invitation r = self.client.post( f"/api/v1/households/{self.slug}/invitations", headers=self.owner_headers, json={"email": "invitee@test.com"}, ) assert r.status_code == 200, r.text body = r.json() invite_link = body.get("invite_link") assert isinstance(invite_link, str) and "/invitations/accept?token=" in invite_link # Extract token from invite_link from urllib.parse import urlparse, parse_qs qs = parse_qs(urlparse(invite_link).query) token_list = qs.get("token", []) assert token_list and isinstance(token_list[0], str) token = token_list[0] assert isinstance(token, str) and len(token) >= 16 # Register invitee r2 = self.client.post( "/api/v1/auth/register", json={"email": "invitee@test.com", "password": "pw", "displayName": "Invitee"}, ) assert r2.status_code == 200, r2.text invitee_headers = {"Authorization": f"Bearer {r2.json()['accessToken']}"} # Accept invitation r3 = self.client.post( "/api/v1/invitations/accept", headers=invitee_headers, json={"token": token} ) assert r3.status_code == 200, r3.text body = r3.json() assert body["status"] == "accepted" # Invitee should now see household in their list r4 = self.client.get("/api/v1/users/me/households", headers=invitee_headers) assert r4.status_code == 200, r4.text households = r4.json() assert any(h["slug"] == self.slug for h in households)