"""Integration tests for auth routes (register / login / confirm-email / logout).""" import secrets from unittest.mock import patch import pytest from web.models.user import User, UserStatusEnum # ── /register ──────────────────────────────────────────────────────────────── @pytest.mark.asyncio async def test_register_get(client): resp = await client.get("/register") assert resp.status_code == 200 assert "Регистрация" in resp.text @pytest.mark.asyncio @patch("web.routes.auth.send_email_task") async def test_register_creates_pending_user(mock_task, client, override_db): resp = await client.post("/register", data={ "first_name": "Иван", "last_name": "Иванов", "email": "ivan@test.com", "phone": "+79001234567", "password": "password123", "password_confirm": "password123", }) assert resp.status_code == 200 assert "Подтвердите" in resp.text user = override_db.query(User).filter(User.email == "ivan@test.com").first() assert user is not None assert user.status == UserStatusEnum.pending assert user.is_email_confirmed is False assert user.email_confirm_token is not None mock_task.delay.assert_called_once() @pytest.mark.asyncio @patch("web.routes.auth.send_email_task") async def test_register_duplicate_email(mock_task, client, active_user): resp = await client.post("/register", data={ "first_name": "X", "last_name": "Y", "email": active_user.email, "phone": "+79999999999", "password": "password123", "password_confirm": "password123", }) assert resp.status_code == 200 assert "уже существует" in resp.text mock_task.delay.assert_not_called() @pytest.mark.asyncio async def test_register_password_mismatch(client): resp = await client.post("/register", data={ "email": "new@test.com", "phone": "+79000000001", "password": "password123", "password_confirm": "different", }) assert resp.status_code == 200 assert "не совпадают" in resp.text @pytest.mark.asyncio async def test_register_short_password(client): resp = await client.post("/register", data={ "email": "new@test.com", "phone": "+79000000002", "password": "short", "password_confirm": "short", }) assert resp.status_code == 200 assert "минимум 8" in resp.text # ── /confirm-email ──────────────────────────────────────────────────────────── @pytest.mark.asyncio async def test_confirm_email_valid_token(client, override_db, user_factory): token = secrets.token_urlsafe(32) user = user_factory.create( is_email_confirmed=False, email_confirm_token=token, status=UserStatusEnum.pending, ) resp = await client.get(f"/confirm-email?token={token}") assert resp.status_code == 200 assert "подтвержден" in resp.text.lower() override_db.refresh(user) assert user.is_email_confirmed is True assert user.status == UserStatusEnum.active assert user.email_confirm_token is None @pytest.mark.asyncio async def test_confirm_email_invalid_token(client): resp = await client.get("/confirm-email?token=bogustoken") assert resp.status_code == 200 assert "Ошибка" in resp.text @pytest.mark.asyncio async def test_confirm_email_missing_token(client): resp = await client.get("/confirm-email") assert resp.status_code == 200 assert "Ошибка" in resp.text # ── /login ──────────────────────────────────────────────────────────────────── @pytest.mark.asyncio async def test_login_get(client): resp = await client.get("/login") assert resp.status_code == 200 assert "Вход" in resp.text @pytest.mark.asyncio async def test_login_success(client, active_user): resp = await client.post("/login", data={ "email": active_user.email, "password": "testpass123", }, follow_redirects=False) assert resp.status_code == 303 assert resp.headers["location"] == "/profile" @pytest.mark.asyncio async def test_login_wrong_password(client, active_user): resp = await client.post("/login", data={ "email": active_user.email, "password": "wrongpassword", }) assert resp.status_code == 200 assert "Неверный" in resp.text @pytest.mark.asyncio async def test_login_unknown_email(client): resp = await client.post("/login", data={ "email": "nobody@test.com", "password": "testpass123", }) assert resp.status_code == 200 assert "Неверный" in resp.text @pytest.mark.asyncio async def test_login_suspended_user(client, user_factory): user = user_factory.create(status=UserStatusEnum.suspended) resp = await client.post("/login", data={ "email": user.email, "password": "testpass123", }) assert resp.status_code == 200 assert "заблокирован" in resp.text.lower() @pytest.mark.asyncio async def test_login_unconfirmed_email(client, user_factory): user = user_factory.create(is_email_confirmed=False, status=UserStatusEnum.pending) resp = await client.post("/login", data={ "email": user.email, "password": "testpass123", }) assert resp.status_code == 200 assert "подтвердите" in resp.text.lower() # ── /logout ─────────────────────────────────────────────────────────────────── @pytest.mark.asyncio async def test_logout_redirects(client): resp = await client.get("/logout", follow_redirects=False) assert resp.status_code == 303 assert resp.headers["location"] == "/login"