Selenium Testing
When to Use
- Browser automation, visual testing
- Mentions: "selenium", "webdriver", "screenshot"
Canonical Repo Rules
For Skriptoteket-specific login/env conventions, follow:
.agents/rules/075-browser-automation.md
Run
bash1pdm run python -m scripts.<module>
Quick Pattern
python1import os 2from pathlib import Path 3 4from selenium import webdriver 5from selenium.webdriver.common.by import By 6from selenium.webdriver.support.ui import WebDriverWait 7from selenium.webdriver.support import expected_conditions as EC 8 9 10def _read_dotenv(path: Path) -> dict[str, str]: 11 if not path.exists(): 12 return {} 13 14 values: dict[str, str] = {} 15 for line in path.read_text(encoding="utf-8").splitlines(): 16 stripped = line.strip() 17 if not stripped or stripped.startswith("#") or "=" not in stripped: 18 continue 19 key, value = stripped.split("=", 1) 20 values[key.strip()] = value.strip() 21 return values 22 23 24dotenv = _read_dotenv(Path(os.environ.get("DOTENV_PATH", ".env"))) 25 26 27def _get_config_value(*, key: str, default: str | None = None) -> str | None: 28 return os.environ.get(key) or dotenv.get(key) or default 29 30 31base_url = _get_config_value(key="BASE_URL", default="http://127.0.0.1:8000") or "http://127.0.0.1:8000" 32email = _get_config_value(key="PLAYWRIGHT_EMAIL") or _get_config_value(key="BOOTSTRAP_SUPERUSER_EMAIL") 33password = _get_config_value(key="PLAYWRIGHT_PASSWORD") or _get_config_value( 34 key="BOOTSTRAP_SUPERUSER_PASSWORD" 35) 36 37if not email or not password: 38 raise SystemExit( 39 "Missing credentials. Either set PLAYWRIGHT_EMAIL/PLAYWRIGHT_PASSWORD (recommended for prod) " 40 "or BOOTSTRAP_SUPERUSER_EMAIL/BOOTSTRAP_SUPERUSER_PASSWORD (dev). " 41 "Provide them in DOTENV_PATH (default: .env) or export them in your shell." 42 ) 43 44options = webdriver.ChromeOptions() 45options.add_argument("--headless=new") 46driver = webdriver.Chrome(options=options) 47driver.set_window_size(1440, 900) 48 49# Login 50driver.get(f"{base_url}/login") 51driver.find_element(By.NAME, "email").send_keys(email) 52driver.find_element(By.NAME, "password").send_keys(password) 53driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click() 54WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//*[contains(., 'Inloggad som')]"))) 55 56# Screenshot 57Path(".artifacts").mkdir(parents=True, exist_ok=True) 58driver.get(f"{base_url}/admin/tools") 59driver.save_screenshot(".artifacts/selenium-admin-tools.png") 60driver.quit()
HTMX Caveat
Use explicit WebDriverWait with EC.url_contains() instead of implicit waits.
Context7
Use mcp__context7__get-library-docs with /seleniumhq/selenium for API details.