import pytest from datetime import datetime, timezone, timedelta from unittest.mock import AsyncMock, patch from sqlalchemy import select @pytest.mark.asyncio async def test_register_auto_sends_verification_email(client, test_db): """Fresh registration triggers send_email_verification_email.""" with patch( "app.core.email.EmailService.send_email_verification_email", new_callable=AsyncMock, ) as mock_send: response = await client.post("/api/v1/auth/register", json={ "email": "newshop@example.com", "password": "Verystrong1Pwd", "name": "New Shop", }) assert response.status_code in (200, 201), response.json() mock_send.assert_called_once() kwargs = mock_send.call_args.kwargs assert kwargs["to_email"] == "newshop@example.com" assert "/verify-email?token=" in kwargs["verification_url"] @pytest.mark.asyncio async def test_register_with_account_invite_code_email_mismatch_rejected( client, test_db, test_user ): """Invite code is for invited@example.com but user registers with a different email -> 400 invite_email_mismatch.""" from app.models.account_invite import AccountInvite import uuid invited_by_id = uuid.UUID(test_user["user_data"]["id"]) account_id = uuid.UUID(test_user["user_data"]["account_id"]) invite = AccountInvite( account_id=account_id, invited_by_id=invited_by_id, email="invited@example.com", code="INVITECODE99", role="engineer", expires_at=datetime.now(timezone.utc) + timedelta(days=7), ) test_db.add(invite) await test_db.commit() response = await client.post("/api/v1/auth/register", json={ "email": "wrong-email@example.com", "password": "Verystrong1Pwd", "name": "Wrong Email", "account_invite_code": "INVITECODE99", }) assert response.status_code == 400, response.json() assert response.json()["detail"]["error"] == "invite_email_mismatch" @pytest.mark.asyncio async def test_register_with_account_invite_code_email_match_accepted( client, test_db, test_user ): """Invite code is for invited@example.com - registering with that email succeeds and joins the existing account.""" from app.models.account_invite import AccountInvite from app.models.user import User import uuid invited_by_id = uuid.UUID(test_user["user_data"]["id"]) account_id = uuid.UUID(test_user["user_data"]["account_id"]) invite = AccountInvite( account_id=account_id, invited_by_id=invited_by_id, email="invited@example.com", code="INVITECODE100", role="engineer", expires_at=datetime.now(timezone.utc) + timedelta(days=7), ) test_db.add(invite) await test_db.commit() with patch( "app.core.email.EmailService.send_email_verification_email", new_callable=AsyncMock, ): response = await client.post("/api/v1/auth/register", json={ "email": "invited@example.com", "password": "Verystrong1Pwd", "name": "Invited", "account_invite_code": "INVITECODE100", }) assert response.status_code in (200, 201), response.json() new_user = (await test_db.execute( select(User).where(User.email == "invited@example.com") )).scalar_one() assert new_user.account_id == account_id # joined existing account