55 lines
1.9 KiB
Python
55 lines
1.9 KiB
Python
import pytest
|
|
from unittest.mock import AsyncMock, patch
|
|
from sqlalchemy import select
|
|
from app.models.account_invite import AccountInvite
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_invite_sends_email_and_stamps_email_sent_at(
|
|
client, test_db, test_user, auth_headers
|
|
):
|
|
"""Regression: today's create_invite does NOT send email. After this task, it MUST."""
|
|
with patch(
|
|
"app.core.email.EmailService.send_account_invite_email",
|
|
new_callable=AsyncMock, return_value=True,
|
|
) as mock_send:
|
|
response = await client.post(
|
|
"/api/v1/accounts/me/invites",
|
|
json={"email": "teammate@example.com", "role": "engineer"},
|
|
headers=auth_headers,
|
|
)
|
|
assert response.status_code == 201, response.json()
|
|
mock_send.assert_called_once()
|
|
kwargs = mock_send.call_args.kwargs
|
|
assert kwargs["to_email"] == "teammate@example.com"
|
|
assert kwargs["role"] == "engineer"
|
|
assert kwargs["code"]
|
|
|
|
invite = (await test_db.execute(
|
|
select(AccountInvite).where(AccountInvite.email == "teammate@example.com")
|
|
)).scalar_one()
|
|
assert invite.email_sent_at is not None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_invite_email_failure_still_creates_row(
|
|
client, test_db, test_user, auth_headers
|
|
):
|
|
"""When EmailService returns False, the invite row is still created but
|
|
email_sent_at remains NULL."""
|
|
with patch(
|
|
"app.core.email.EmailService.send_account_invite_email",
|
|
new_callable=AsyncMock, return_value=False,
|
|
):
|
|
response = await client.post(
|
|
"/api/v1/accounts/me/invites",
|
|
json={"email": "fail-mail@example.com", "role": "engineer"},
|
|
headers=auth_headers,
|
|
)
|
|
assert response.status_code == 201
|
|
|
|
invite = (await test_db.execute(
|
|
select(AccountInvite).where(AccountInvite.email == "fail-mail@example.com")
|
|
)).scalar_one()
|
|
assert invite.email_sent_at is None
|