""" Generic Load Test - Login to Assessments Page A transparent, world-class load testing mechanism that: 1. Logs in all users 2. Navigates to Assessments page 3. Verifies page renders fully 4. Tests scroll smoothness 5. Provides comprehensive tracking This is a generic framework that can be extended with any test case. Updated to use Assessments flow instead of Cognition Test. """ import pytest from concurrent.futures import ThreadPoolExecutor, as_completed import threading from utils.load_test_base import LoadTestBase, LoadTestResult, TestStatus from datetime import datetime from pages.login_page import LoginPage from pages.dashboard_page import DashboardPage # NOTE: CognitionTestPage removed - using Assessments flow instead # from pages.cognition_test_page import CognitionTestPage from pages.assessments_page import AssessmentsPage from utils.driver_manager import DriverManager from config.config import BASE_URL from pathlib import Path def login_and_navigate_to_assessments(user_id: int, headless: bool = True) -> dict: """ Generic test function: Login and navigate to Assessments page This is a simple, focused test that verifies: - Login works - Navigation works - Page renders fully - Page scrolls smoothly Args: user_id: Unique user identifier headless: Whether to run in headless mode (default: True for load testing) Returns: dict: Test result with driver and steps completed """ driver = None steps_completed = [] try: # Step 1: Create WebDriver (headless configurable) driver = DriverManager.get_driver(headless=headless) steps_completed.append(f"User {user_id}: WebDriver created") # Step 2: Login login_page = LoginPage(driver) login_page.login() steps_completed.append(f"User {user_id}: Login successful") # Step 3: Navigate to Dashboard dashboard_page = DashboardPage(driver) dashboard_page.navigate() steps_completed.append(f"User {user_id}: Dashboard loaded") # Step 4: Handle profile modal if present if dashboard_page.is_profile_modal_present(): dashboard_page.handle_profile_completion_modal() steps_completed.append(f"User {user_id}: Profile modal handled") # Step 5: Navigate to Assessments page (replacing old Cognition Test) from pages.student_nav_page import StudentNavPage nav_page = StudentNavPage(driver) nav_page.click_assessments() steps_completed.append(f"User {user_id}: Navigated to Assessments page") # Step 6: Verify Assessments page loaded assessments_page = AssessmentsPage(driver) assessments_page.wait_for_page_load() steps_completed.append(f"User {user_id}: Assessments page loaded") # Step 7: Verify page loaded (check URL) assert "/assessments" in driver.current_url, "Should be on assessments page" steps_completed.append(f"User {user_id}: Page verified (assessments page rendered)") # Step 8: Test scroll smoothness # Scroll to bottom driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") steps_completed.append(f"User {user_id}: Scrolled to bottom") # Scroll to top driver.execute_script("window.scrollTo(0, 0);") steps_completed.append(f"User {user_id}: Scrolled to top") # Step 9: Verify page is fully rendered page_ready = driver.execute_script("return document.readyState === 'complete'") if page_ready: steps_completed.append(f"User {user_id}: Page fully rendered") # Return result with driver (metrics will be measured by base class) # Driver will be cleaned up after metrics are collected return { 'driver': driver, 'steps_completed': steps_completed, 'success': True } except Exception as e: error_msg = f"User {user_id}: ERROR - {type(e).__name__}: {str(e)}" steps_completed.append(error_msg) # Print error for debugging print(f" ❌ {error_msg}") if driver: try: DriverManager.quit_driver(driver) except: pass raise # Note: Driver cleanup happens in the base class or caller class GenericLoadTest(LoadTestBase): """Generic load test executor""" def __init__(self, test_name: str = "Login to Assessments"): super().__init__(test_name) self.lock = threading.Lock() def run_load_test( self, num_users: int, ramp_up_time: int = 0, max_workers: int = None, headless: bool = True ) -> dict: """ Run load test with comprehensive tracking Args: num_users: Number of concurrent users ramp_up_time: Time to gradually ramp up users (seconds) max_workers: Maximum concurrent workers Returns: dict: Summary and results """ print(f"\n{'='*80}") print(f"🚀 STARTING LOAD TEST: {self.test_name}") print(f"{'='*80}") print(f"📊 Configuration:") print(f" Users: {num_users}") print(f" Ramp-up: {ramp_up_time}s") print(f" Max Workers: {max_workers or 'Unlimited'}") print(f"{'='*80}\n") self.start_time = datetime.now() self.results = [] delay_per_user = ramp_up_time / num_users if ramp_up_time > 0 else 0 with ThreadPoolExecutor(max_workers=max_workers) as executor: futures = [] for user_id in range(1, num_users + 1): # Ramp-up delay if delay_per_user > 0: import time time.sleep(delay_per_user) # Submit test execution with headless parameter future = executor.submit( self.execute_test_for_user, user_id, login_and_navigate_to_assessments, headless=headless ) futures.append((user_id, future)) if user_id % 10 == 0: print(f" ⏳ Started {user_id}/{num_users} users...") # Wait for all to complete and collect results print(f"\n ⏳ Waiting for all {num_users} users to complete...\n") completed = 0 for user_id, future in futures: try: result = future.result() with self.lock: self.results.append(result) completed += 1 if completed % 10 == 0: print(f" ✅ Completed {completed}/{num_users} users...") except Exception as e: print(f" ❌ User {user_id} failed: {str(e)}") self.end_time = datetime.now() # Calculate summary summary = self.calculate_summary() # Print summary self.print_summary(summary) # Save results self.save_results(summary) return { 'summary': summary, 'results': self.results } @pytest.mark.load_test class TestGenericLoadTest: """Generic load tests""" @pytest.mark.parametrize("num_users", [10, 50, 100, 200, 500]) def test_login_to_assessments_load(self, num_users): """ Load test: Login and navigate to Assessments page Tests: - Login functionality under load - Navigation under load - Page rendering under load - Scroll smoothness under load Args: num_users: Number of concurrent users """ load_test = GenericLoadTest("Login to Assessments") result = load_test.run_load_test( num_users=num_users, ramp_up_time=0, max_workers=num_users ) summary = result['summary'] # Assertions assert summary.success_rate >= 80, \ f"Success rate {summary.success_rate:.2f}% is below 80%" assert summary.scroll_smooth_rate >= 90, \ f"Scroll smooth rate {summary.scroll_smooth_rate:.2f}% is below 90%" assert summary.avg_page_load_time < 10, \ f"Average page load time {summary.avg_page_load_time:.2f}s exceeds 10s" # Standalone execution def run_generic_load_test(num_users: int = 100): """ Standalone function to run generic load test Args: num_users: Number of concurrent users """ load_test = GenericLoadTest("Login to Assessments") return load_test.run_load_test(num_users=num_users) if __name__ == "__main__": import sys num_users = int(sys.argv[1]) if len(sys.argv) > 1 else 100 run_generic_load_test(num_users=num_users)