247 lines
10 KiB
Python
247 lines
10 KiB
Python
"""
|
|
WebDriver Manager for Cognitive Prism Automation Tests
|
|
"""
|
|
import os
|
|
from selenium import webdriver
|
|
from selenium.webdriver.chrome.service import Service
|
|
from selenium.webdriver.chrome.options import Options
|
|
from selenium.webdriver.firefox.service import Service as FirefoxService
|
|
from selenium.webdriver.firefox.options import Options as FirefoxOptions
|
|
from selenium.webdriver.edge.service import Service as EdgeService
|
|
from selenium.webdriver.edge.options import Options as EdgeOptions
|
|
from webdriver_manager.chrome import ChromeDriverManager
|
|
from webdriver_manager.firefox import GeckoDriverManager
|
|
from webdriver_manager.microsoft import EdgeChromiumDriverManager
|
|
from config.config import (
|
|
BROWSER, HEADLESS, IMPLICIT_WAIT, PAGE_LOAD_TIMEOUT, DOWNLOAD_DIR
|
|
)
|
|
|
|
|
|
class DriverManager:
|
|
"""Manages WebDriver instances"""
|
|
|
|
@staticmethod
|
|
def get_driver(headless=None):
|
|
"""
|
|
Creates and returns a WebDriver instance based on configuration
|
|
|
|
Args:
|
|
headless: Force headless mode (None = use config, True = headless, False = visible)
|
|
|
|
Returns:
|
|
WebDriver: Configured WebDriver instance
|
|
"""
|
|
if BROWSER == "chrome":
|
|
return DriverManager._get_chrome_driver(headless=headless)
|
|
elif BROWSER == "firefox":
|
|
return DriverManager._get_firefox_driver(headless=headless)
|
|
elif BROWSER == "edge":
|
|
return DriverManager._get_edge_driver(headless=headless)
|
|
else:
|
|
raise ValueError(f"Unsupported browser: {BROWSER}")
|
|
|
|
@staticmethod
|
|
def _get_chrome_driver(headless=None):
|
|
"""
|
|
Creates and returns Chrome WebDriver
|
|
|
|
Args:
|
|
headless: Force headless mode (None = use config, True = headless, False = visible)
|
|
"""
|
|
options = Options()
|
|
|
|
# Determine headless mode
|
|
use_headless = headless if headless is not None else HEADLESS
|
|
|
|
if use_headless:
|
|
options.add_argument("--headless")
|
|
options.add_argument("--disable-gpu")
|
|
|
|
# Performance options (important for load testing)
|
|
options.add_argument("--no-sandbox")
|
|
options.add_argument("--disable-dev-shm-usage")
|
|
options.add_argument("--window-size=1920,1080")
|
|
# Additional performance optimizations for load testing
|
|
if use_headless:
|
|
options.add_argument("--disable-extensions")
|
|
options.add_argument("--disable-plugins")
|
|
# Note: --disable-images might break some tests, so we'll skip it for now
|
|
|
|
# Download preferences
|
|
prefs = {
|
|
"download.default_directory": DOWNLOAD_DIR,
|
|
"download.prompt_for_download": False,
|
|
"download.directory_upgrade": True,
|
|
"safebrowsing.enabled": True
|
|
}
|
|
options.add_experimental_option("prefs", prefs)
|
|
|
|
# Get ChromeDriver path - webdriver-manager may return directory or file path
|
|
driver_path = ChromeDriverManager().install()
|
|
original_path = driver_path
|
|
|
|
# Handle case where webdriver-manager returns a file path instead of directory
|
|
if os.path.isfile(driver_path):
|
|
# If it's a file, check if it's the actual executable
|
|
file_size = os.path.getsize(driver_path)
|
|
if file_size > 10000000: # > 10MB is definitely the executable
|
|
# This is the actual chromedriver executable
|
|
pass # Use it as-is
|
|
else:
|
|
# It's not the executable, search in parent directory
|
|
driver_path = os.path.dirname(driver_path)
|
|
original_path = driver_path
|
|
|
|
# Ensure we have the actual chromedriver executable, not a directory or text file
|
|
if os.path.isdir(driver_path):
|
|
# Strategy: Search for files named exactly "chromedriver" (no extension, no prefix)
|
|
# and pick the largest one (executable is 10-20MB, text files are < 1MB)
|
|
candidate_files = []
|
|
|
|
# Search directory tree for files named exactly "chromedriver"
|
|
for root, dirs, files in os.walk(original_path):
|
|
for file in files:
|
|
# CRITICAL: File must be named EXACTLY "chromedriver" with no extension
|
|
# This excludes "THIRD_PARTY_NOTICES.chromedriver", "LICENSE.chromedriver", etc.
|
|
# Use strict equality check - file name must be exactly "chromedriver"
|
|
if file == "chromedriver" and len(file) == 12: # "chromedriver" is 12 chars
|
|
full_path = os.path.join(root, file)
|
|
if os.path.isfile(full_path):
|
|
file_size = os.path.getsize(full_path)
|
|
# Only consider files > 1MB (executable size threshold)
|
|
if file_size > 1000000:
|
|
candidate_files.append((full_path, file_size))
|
|
|
|
# If we found candidate files, pick the largest one
|
|
if candidate_files:
|
|
# Sort by size (largest first)
|
|
candidate_files.sort(key=lambda x: x[1], reverse=True)
|
|
# Pick the largest file - this should be the actual executable (10-20MB)
|
|
driver_path = candidate_files[0][0]
|
|
file_size = candidate_files[0][1]
|
|
|
|
# Validate it's large enough (should be > 10MB for ChromeDriver)
|
|
if file_size < 10000000: # Less than 10MB is suspicious
|
|
# But allow if it's at least > 1MB and we have no better option
|
|
if file_size < 1000000:
|
|
raise FileNotFoundError(
|
|
f"Found chromedriver file but size ({file_size} bytes) is too small.\n"
|
|
f"Expected > 1MB. Path: {driver_path}\n"
|
|
f"Found {len(candidate_files)} candidate file(s)."
|
|
)
|
|
else:
|
|
# No candidate files found
|
|
raise FileNotFoundError(
|
|
f"ChromeDriver executable not found in {original_path}.\n"
|
|
f"Searched for files named exactly 'chromedriver' with size > 1MB."
|
|
)
|
|
|
|
# Final validation - ensure it's a file
|
|
if not os.path.isfile(driver_path):
|
|
raise FileNotFoundError(
|
|
f"ChromeDriver executable not found. Searched in: {original_path}\n"
|
|
f"Please ensure ChromeDriver is properly installed."
|
|
)
|
|
|
|
# Verify it's the actual executable (large file, not text file)
|
|
file_size = os.path.getsize(driver_path)
|
|
if file_size < 1000000: # Less than 1MB is likely not the executable
|
|
raise FileNotFoundError(
|
|
f"Found chromedriver file but it appears to be a text file (size: {file_size} bytes).\n"
|
|
f"Expected executable size > 1MB. Path: {driver_path}\n"
|
|
f"Please check the ChromeDriver installation."
|
|
)
|
|
|
|
# Make it executable if needed
|
|
if not os.access(driver_path, os.X_OK):
|
|
os.chmod(driver_path, 0o755)
|
|
if not os.access(driver_path, os.X_OK):
|
|
raise PermissionError(
|
|
f"ChromeDriver at {driver_path} is not executable and could not be made executable."
|
|
)
|
|
|
|
service = Service(driver_path)
|
|
driver = webdriver.Chrome(service=service, options=options)
|
|
|
|
# Set timeouts
|
|
driver.implicitly_wait(IMPLICIT_WAIT)
|
|
driver.set_page_load_timeout(PAGE_LOAD_TIMEOUT)
|
|
|
|
return driver
|
|
|
|
@staticmethod
|
|
def _get_firefox_driver(headless=None):
|
|
"""
|
|
Creates and returns Firefox WebDriver
|
|
|
|
Args:
|
|
headless: Force headless mode (None = use config, True = headless, False = visible)
|
|
"""
|
|
options = FirefoxOptions()
|
|
|
|
# Determine headless mode
|
|
use_headless = headless if headless is not None else HEADLESS
|
|
|
|
if use_headless:
|
|
options.add_argument("--headless")
|
|
|
|
# Download preferences
|
|
options.set_preference("browser.download.folderList", 2)
|
|
options.set_preference("browser.download.dir", DOWNLOAD_DIR)
|
|
options.set_preference("browser.download.useDownloadDir", True)
|
|
options.set_preference("browser.helperApps.neverAsk.saveToDisk",
|
|
"application/json,text/csv")
|
|
|
|
service = FirefoxService(GeckoDriverManager().install())
|
|
driver = webdriver.Firefox(service=service, options=options)
|
|
|
|
# Set timeouts
|
|
driver.implicitly_wait(IMPLICIT_WAIT)
|
|
driver.set_page_load_timeout(PAGE_LOAD_TIMEOUT)
|
|
|
|
return driver
|
|
|
|
@staticmethod
|
|
def _get_edge_driver(headless=None):
|
|
"""
|
|
Creates and returns Edge WebDriver
|
|
|
|
Args:
|
|
headless: Force headless mode (None = use config, True = headless, False = visible)
|
|
"""
|
|
options = EdgeOptions()
|
|
|
|
# Determine headless mode
|
|
use_headless = headless if headless is not None else HEADLESS
|
|
|
|
if use_headless:
|
|
options.add_argument("--headless")
|
|
|
|
options.add_argument("--no-sandbox")
|
|
options.add_argument("--disable-dev-shm-usage")
|
|
options.add_argument("--window-size=1920,1080")
|
|
|
|
# Download preferences
|
|
prefs = {
|
|
"download.default_directory": DOWNLOAD_DIR,
|
|
"download.prompt_for_download": False,
|
|
"download.directory_upgrade": True
|
|
}
|
|
options.add_experimental_option("prefs", prefs)
|
|
|
|
service = EdgeService(EdgeChromiumDriverManager().install())
|
|
driver = webdriver.Edge(service=service, options=options)
|
|
|
|
# Set timeouts
|
|
driver.implicitly_wait(IMPLICIT_WAIT)
|
|
driver.set_page_load_timeout(PAGE_LOAD_TIMEOUT)
|
|
|
|
return driver
|
|
|
|
@staticmethod
|
|
def quit_driver(driver):
|
|
"""Quits the WebDriver instance"""
|
|
if driver:
|
|
driver.quit()
|
|
|