# tests/test_e2e_authentication.py import pytest from playwright.sync_api import Page, expect from e2e.e2e_constants import Login from e2e.e2e_helper import locate, fill, debug, check_not_in_content from playwright_config import BASE_URL class TestAuthentication: """Tests for authentication and login functionality""" @pytest.mark.e2e @pytest.mark.smoke def test_unauthenticated_user_redirected_to_login(self, app_server, page: Page): """Test that when not logged in, the default page is the login page""" # Navigate to the root URL page.goto(BASE_URL) # Wait for the page to fully load page.wait_for_load_state("networkidle") # Check that we're on the login page # Option 1: Check URL contains login-related path expect(page).to_have_url(f"{BASE_URL}/authlogin/login") # Option 2: Check for login form elements # Look for typical login form elements login_indicators = [ "input[type='email']", "input[type='password']", "input[name*='username']", "input[name*='email']", "input[name*='password']", "button[type='submit']", "form" ] # At least one login indicator should be present login_form_found = False for selector in login_indicators: if page.locator(selector).count() > 0: login_form_found = True break assert login_form_found, "No login form elements found on the page" # Option 3: Check for login-related text content page_content = page.content().lower() login_keywords = ["login", "sign in", "authenticate", "username", "password", "email"] has_login_content = any(keyword in page_content for keyword in login_keywords) assert has_login_content, "Page does not contain login-related content" # Option 4: Ensure we're not on a protected page # Check that we don't see protected content like "dashboard", "logout", "profile", "settings"] protected_content = ["dashboard", "logout", "profile", "settings"] page_text = page.locator("body").inner_text().lower() for protected_word in protected_content: assert protected_word not in page_text, f"Found protected content '{protected_word}' when not logged in" @pytest.mark.e2e @pytest.mark.regression def test_login_page_has_required_elements(self, app_server, page: Page): """Test that the login page contains all required elements""" page.goto(BASE_URL) page.wait_for_load_state("networkidle") # Check for essential login form elements expect(page.locator("form")).to_be_visible() # Check for input fields (at least email/username and password) username_input = page.locator("input[type='email'], input[name*='username'], input[name*='email']") expect(username_input.first).to_be_visible() password_input = page.locator("input[type='password'], input[name*='password']") expect(password_input.first).to_be_visible() # Check for submit button submit_button = page.locator("button[type='submit'], input[type='submit']") expect(submit_button.first).to_be_visible() def test_page_loads_without_errors(self, app_server, page: Page): """Test that the login page loads without console errors""" console_errors = [] def handle_console(msg): if msg.type == "error": console_errors.append(msg.text) page.on("console", handle_console) page.goto(BASE_URL) page.wait_for_load_state("networkidle") # Check for console errors assert len(console_errors) == 0, f"Console errors found: {console_errors}" # Check that the page actually loaded (not a 404 or 500 error) expect(page.locator("body")).to_be_visible() # Check that the page has a title expect(page).to_have_title("My Managing Tools") # New test to validate database isolation @pytest.mark.e2e @pytest.mark.smoke def test_test_database_isolation(self, app_server, test_database, test_users): """Test that application uses isolated test database""" import os # Verify test environment variables are configured assert os.environ.get("DB_PATH") == test_database assert os.environ.get("ADMIN_EMAIL") == test_users["admin"]["email"] assert os.environ.get("ADMIN_PASSWORD") == test_users["admin"]["password"] # Verify temporary database file exists assert os.path.exists(test_database), f"Test database file not found: {test_database}" # Verify path contains 'test_mmt_' to confirm isolation assert "test_mmt_" in test_database, "Database path should contain test prefix" print(f"✅ Test database isolation confirmed: {test_database}") # ============================================================================= # PRIORITY 1 TESTS - CRITICAL AUTHENTICATION FLOWS # ============================================================================= @pytest.mark.e2e @pytest.mark.priority1 @pytest.mark.smoke def test_successful_login_with_valid_credentials(self, app_server, test_users, page: Page): """ Priority 1 Test: Validate complete successful login flow with valid credentials This test ensures that: 1. User can access the login page 2. User can enter valid credentials 3. Form submission works correctly 4. User is redirected to home page after successful authentication 5. User session is properly established """ admin_user = test_users["admin"] # Step 1: Navigate to login page page.goto(BASE_URL) page.wait_for_load_state("networkidle") # Verify we're on the login page expect(page).to_have_url(f"{BASE_URL}/authlogin/login") # Step 2: Locate form elements email_input = locate(page, Login.email) password_input = locate(page, Login.password) submit_button = locate(page, Login.submit) fill(email_input, admin_user["email"]) fill(password_input, admin_user["password"]) with page.expect_navigation(wait_until="networkidle"): submit_button.click() debug(page, "after_login") check_not_in_content(page, ["sign in", "login", "authenticate"]) page.pause() # Step 5: Verify successful authentication and redirect # Should be redirected to the home page expect(page).to_have_url(BASE_URL + "/") # Step 6: Verify we're actually authenticated (not redirected back to login) # The page should load without being redirected back to login page.wait_for_load_state("networkidle") current_url = page.url assert not current_url.endswith("/authlogin/login"), f"User was redirected back to login page: {current_url}" # Step 7: Verify authenticated content is present # Check that we don't see login-related content anymore page_content = page.content().lower() login_keywords = ["sign in", "login", "authenticate"] # Should not see login form elements on authenticated page has_login_content = any(keyword in page_content for keyword in login_keywords) assert not has_login_content, "Login content still visible after successful authentication" # Step 8: Verify no error messages are displayed # Look for common error message containers error_selectors = [ ".error", ".alert-error", ".bg-error", "[class*='error']", ".text-red", "[class*='text-red']" ] for error_selector in error_selectors: error_elements = page.locator(error_selector) if error_elements.count() > 0: # If error elements exist, they should not be visible or should be empty for i in range(error_elements.count()): element = error_elements.nth(i) if element.is_visible(): element_text = element.inner_text().strip() assert not element_text, f"Error message found after successful login: {element_text}" # Step 9: Verify the page has expected title expect(page).to_have_title("My Managing Tools") print(f"✅ Successful login test completed - User {admin_user['email']} authenticated successfully")