Files
MyManagingTools/tests/test_e2e_authentication.py

256 lines
9.8 KiB
Python

# tests/test_e2e_authentication.py
import pytest
from playwright.sync_api import Page, expect
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 = page.locator("input[type='email'], input[name='email']")
password_input = page.locator("input[type='password'], input[name='password']")
submit_button = page.locator("button[type='submit']")
# Verify all required elements are present and visible
expect(email_input).to_be_visible()
expect(password_input).to_be_visible()
expect(submit_button).to_be_visible()
# Step 3: Fill in valid credentials
email_input.fill(admin_user["email"])
password_input.fill(admin_user["password"])
# Verify credentials were entered correctly
expect(email_input).to_have_value(admin_user["email"])
expect(password_input).to_have_value(admin_user["password"])
# Step 4: Submit the login form
# Use click with wait for navigation to handle the redirect
with page.expect_navigation(wait_until="networkidle"):
submit_button.click()
# DEBUGGING BLOCK - Add this
print(f"🔍 Current URL: {page.url}")
print(f"🔍 Page title: {page.title()}")
# Take screenshot
page.screenshot(path="debug_after_login.png")
# Save full HTML for inspection
with open("debug_page.html", "w", encoding="utf-8") as f:
f.write(page.content())
# Check specific content that's causing the failure
page_content = page.content().lower()
login_keywords = ["sign in", "login", "authenticate"]
print("🔍 Checking for login keywords:")
for keyword in login_keywords:
if keyword in page_content:
print(f" ❌ Found '{keyword}' in page content")
# Find exactly where this keyword appears
occurrences = page.get_by_text(keyword, exact=False)
count = occurrences.count()
print(f" Found in {count} elements:")
for i in range(min(count, 3)): # Show first 3 occurrences
element = occurrences.nth(i)
try:
print(f" - Element {i}: '{element.inner_text()[:50]}...' (visible: {element.is_visible()})")
except:
print(f" - Element {i}: Could not get text")
else:
print(f"'{keyword}' NOT found")
# Your original assertion (will still fail, but now you have debug info)
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"
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")