""" E2E tests for user registration and authentication flows. These tests verify the complete user journey for registration, login, and account management using Playwright for browser automation. """ import pytest from playwright.sync_api import Page, expect @pytest.mark.e2e class TestUserRegistration: """E2E tests for user registration flow.""" def test__registration_page__displays_form(self, page: Page, live_server): """Test registration page displays the registration form.""" page.goto(f"{live_server.url}/accounts/signup/") # Verify form fields are visible expect(page.get_by_label("Username")).to_be_visible() expect(page.get_by_label("Email")).to_be_visible() expect(page.get_by_label("Password", exact=False).first).to_be_visible() def test__registration__valid_data__creates_account(self, page: Page, live_server): """Test registration with valid data creates an account.""" page.goto(f"{live_server.url}/accounts/signup/") # Fill registration form page.get_by_label("Username").fill("e2e_newuser") page.get_by_label("Email").fill("e2e_newuser@example.com") # Handle password fields (may be "Password" and "Confirm Password" or similar) password_fields = page.locator("input[type='password']") if password_fields.count() >= 2: password_fields.nth(0).fill("SecurePass123!") password_fields.nth(1).fill("SecurePass123!") else: password_fields.first.fill("SecurePass123!") # Submit form page.get_by_role("button", name="Sign Up").click() # Should redirect to success page or login page.wait_for_url("**/*", timeout=5000) def test__registration__duplicate_username__shows_error( self, page: Page, live_server, regular_user ): """Test registration with duplicate username shows error.""" page.goto(f"{live_server.url}/accounts/signup/") # Try to register with existing username page.get_by_label("Username").fill("testuser") page.get_by_label("Email").fill("different@example.com") password_fields = page.locator("input[type='password']") if password_fields.count() >= 2: password_fields.nth(0).fill("SecurePass123!") password_fields.nth(1).fill("SecurePass123!") else: password_fields.first.fill("SecurePass123!") page.get_by_role("button", name="Sign Up").click() # Should show error message error = page.locator(".error, .errorlist, [role='alert']") expect(error.first).to_be_visible() def test__registration__weak_password__shows_error(self, page: Page, live_server): """Test registration with weak password shows validation error.""" page.goto(f"{live_server.url}/accounts/signup/") page.get_by_label("Username").fill("e2e_weakpass") page.get_by_label("Email").fill("e2e_weakpass@example.com") password_fields = page.locator("input[type='password']") if password_fields.count() >= 2: password_fields.nth(0).fill("123") password_fields.nth(1).fill("123") else: password_fields.first.fill("123") page.get_by_role("button", name="Sign Up").click() # Should show password validation error error = page.locator(".error, .errorlist, [role='alert']") expect(error.first).to_be_visible() @pytest.mark.e2e class TestUserLogin: """E2E tests for user login flow.""" def test__login_page__displays_form(self, page: Page, live_server): """Test login page displays the login form.""" page.goto(f"{live_server.url}/accounts/login/") expect(page.get_by_label("Username")).to_be_visible() expect(page.get_by_label("Password")).to_be_visible() expect(page.get_by_role("button", name="Sign In")).to_be_visible() def test__login__valid_credentials__authenticates( self, page: Page, live_server, regular_user ): """Test login with valid credentials authenticates user.""" page.goto(f"{live_server.url}/accounts/login/") page.get_by_label("Username").fill("testuser") page.get_by_label("Password").fill("testpass123") page.get_by_role("button", name="Sign In").click() # Should redirect away from login page page.wait_for_url("**/*") expect(page).not_to_have_url("**/login/**") def test__login__invalid_credentials__shows_error(self, page: Page, live_server): """Test login with invalid credentials shows error.""" page.goto(f"{live_server.url}/accounts/login/") page.get_by_label("Username").fill("nonexistent") page.get_by_label("Password").fill("wrongpass") page.get_by_role("button", name="Sign In").click() # Should show error message error = page.locator(".error, .errorlist, [role='alert'], .alert-danger") expect(error.first).to_be_visible() def test__login__remember_me__checkbox_present(self, page: Page, live_server): """Test login page has remember me checkbox.""" page.goto(f"{live_server.url}/accounts/login/") remember_me = page.locator( "input[name='remember'], input[type='checkbox'][id*='remember']" ) if remember_me.count() > 0: expect(remember_me.first).to_be_visible() @pytest.mark.e2e class TestUserLogout: """E2E tests for user logout flow.""" def test__logout__clears_session(self, auth_page: Page, live_server): """Test logout clears user session.""" # User is already logged in via auth_page fixture # Find and click logout button/link logout = auth_page.locator( "a[href*='logout'], button:has-text('Log Out'), button:has-text('Sign Out')" ) if logout.count() > 0: logout.first.click() # Should be logged out auth_page.wait_for_url("**/*") # Try to access protected page auth_page.goto(f"{live_server.url}/accounts/profile/") # Should redirect to login expect(auth_page).to_have_url("**/login/**") @pytest.mark.e2e class TestPasswordReset: """E2E tests for password reset flow.""" def test__password_reset_page__displays_form(self, page: Page, live_server): """Test password reset page displays the form.""" page.goto(f"{live_server.url}/accounts/password/reset/") email_input = page.locator( "input[type='email'], input[name='email']" ) expect(email_input.first).to_be_visible() def test__password_reset__valid_email__shows_confirmation( self, page: Page, live_server, regular_user ): """Test password reset with valid email shows confirmation.""" page.goto(f"{live_server.url}/accounts/password/reset/") email_input = page.locator("input[type='email'], input[name='email']") email_input.first.fill("testuser@example.com") page.get_by_role("button", name="Reset Password").click() # Should show confirmation message page.wait_for_timeout(500) # Look for success message or confirmation page success = page.locator( ".success, .alert-success, [role='alert']" ) # Or check URL changed to done page if success.count() == 0: expect(page).to_have_url("**/done/**") @pytest.mark.e2e class TestUserProfile: """E2E tests for user profile management.""" def test__profile_page__displays_user_info(self, auth_page: Page, live_server): """Test profile page displays user information.""" auth_page.goto(f"{live_server.url}/accounts/profile/") # Should display username expect(auth_page.get_by_text("testuser")).to_be_visible() def test__profile_page__edit_profile_link(self, auth_page: Page, live_server): """Test profile page has edit profile link/button.""" auth_page.goto(f"{live_server.url}/accounts/profile/") edit_link = auth_page.locator( "a[href*='edit'], button:has-text('Edit')" ) if edit_link.count() > 0: expect(edit_link.first).to_be_visible() def test__profile_edit__updates_info(self, auth_page: Page, live_server): """Test editing profile updates user information.""" auth_page.goto(f"{live_server.url}/accounts/profile/edit/") # Find bio/about field if present bio_field = auth_page.locator( "textarea[name='bio'], textarea[name='about']" ) if bio_field.count() > 0: bio_field.first.fill("Updated bio from E2E test") auth_page.get_by_role("button", name="Save").click() # Should redirect back to profile auth_page.wait_for_url("**/profile/**") @pytest.mark.e2e class TestProtectedRoutes: """E2E tests for protected route access.""" def test__protected_route__unauthenticated__redirects_to_login( self, page: Page, live_server ): """Test accessing protected route redirects to login.""" page.goto(f"{live_server.url}/accounts/profile/") # Should redirect to login expect(page).to_have_url("**/login/**") def test__protected_route__authenticated__allows_access( self, auth_page: Page, live_server ): """Test authenticated user can access protected routes.""" auth_page.goto(f"{live_server.url}/accounts/profile/") # Should not redirect to login expect(auth_page).not_to_have_url("**/login/**") def test__admin_route__regular_user__denied(self, auth_page: Page, live_server): """Test regular user cannot access admin routes.""" auth_page.goto(f"{live_server.url}/admin/") # Should show login or forbidden # Admin login page or 403 def test__moderator_route__moderator__allows_access( self, mod_page: Page, live_server ): """Test moderator can access moderation routes.""" mod_page.goto(f"{live_server.url}/moderation/") # Should not redirect to login (moderator has access) expect(mod_page).not_to_have_url("**/login/**")