Automate Web Testing with Selenium Scripts
Expert Selenium test-script patterns: Page Object Model, robust locators, explicit waits, dynamic content handling, and retry-safe error handling.
Maintainer of this project? Claim this page to edit the listing.
1.0.0Add to Favorites
Why it matters
Create robust and maintainable Selenium test scripts for web applications. This asset leverages Page Object Model, explicit waits, and reliable element locators to ensure thorough and efficient testing.
Outcomes
What it gets done
Generate Selenium test scripts using Page Object Model.
Implement explicit waits for synchronization.
Utilize robust element location strategies.
Handle advanced interactions like dynamic content and window management.
Install
Add it to your toolbox
Run in your project directory:
curl -fsSL https://spark.entire.vc/get/vb-selenium-test-script | bash Overview
Selenium Test Script Expert
Expert Selenium test-script patterns covering Page Object Model structure, robust locator strategies, explicit-wait synchronization, dynamic content handling (dropdowns, uploads, hovers, frames), and retry-safe error handling for stale elements and timeouts. Use when writing or refactoring Selenium/WebDriver test scripts in Python/pytest for maintainability and reduced flakiness. Not a general test-strategy or non-Selenium automation guide.
What it does
Acts as an expert in writing robust, maintainable Selenium test scripts, covering WebDriver APIs, element location strategies, synchronization patterns, and modern testing framework structure. Its central recommendation is always structuring tests with the Page Object Model (POM), separating page logic (locators and interaction methods, like enter_email, click_login, get_error_message on a LoginPage class) from test logic, with each page method using WebDriverWait and expected_conditions rather than touching elements directly.
On element location it recommends stable strategies - By.ID on a unique ID, By.CSS_SELECTOR targeting a data-testid attribute, or By.XPATH matching visible text - and explicitly warns against brittle locators like position-dependent absolute XPath (/html/body/div[3]/form/button[2]) or overly generic class names (By.CLASS_NAME, "btn"). On synchronization it insists on explicit waits over implicit waits or sleep() calls, wrapping them in a reusable BasePage class with helpers like wait_for_element_clickable, wait_for_element_visible, wait_for_text_present, and a is_element_present check that catches TimeoutException to return a boolean rather than raising.
For test structure it shows a pytest-based TestLogin class with an autouse fixture that configures headless Chrome (--headless, --no-sandbox, --disable-dev-shm-usage), instantiates the page object, and tears down the driver after each test, plus a parametrized negative-test pattern (@pytest.mark.parametrize) covering missing email, invalid email format, and missing password cases against expected error messages.
Advanced interaction helpers cover handling dropdowns via Selenium's Select class, file uploads via send_keys with an absolute file path, hover actions via ActionChains, and JavaScript-forced clicks via execute_script for elements that resist normal .click() calls - plus window and frame management (switching to the newest window handle, switching into and back out of iframes).
Driver configuration shows a get_chrome_driver() factory that disables extensions and GPU, sets a fixed window size, and conditionally adds --headless based on a HEADLESS environment variable for CI/CD. Error handling shows a safe_click retry wrapper that catches StaleElementReferenceException (retrying with a short sleep) and TimeoutException (refreshing the page before retrying), re-raising only after exhausting the retry budget.
Eight closing recommendations: collaborate with developers to add data-testid attributes for reliable selection; capture screenshots on test failure; use pytest-html for HTML test reports; use pytest-xdist for parallel execution; keep environment-specific configuration files for dev/staging/prod; review and update locators regularly as the app evolves; test across multiple browsers via a WebDriver manager or cloud service; and use Appium with similar patterns for mobile web testing.
When to use - and when NOT to
Use this skill when writing or refactoring Selenium test scripts that need to be maintainable and resistant to flakiness - adopting Page Object Model structure, replacing brittle locators or sleep-based waits, or adding retry logic for stale elements and timeouts. It is scoped to Selenium/WebDriver specifically and Python/pytest conventions; it is not a general test-strategy or non-Selenium browser-automation guide.
Inputs and outputs
Input is a description of the UI testing scenario (e.g. "login flow test," "dropdown and file upload handling"). Output is Selenium Python test code following POM structure, explicit-wait synchronization, and the retry/error-handling patterns above.
Integrations
Built around Selenium WebDriver (selenium.webdriver, WebDriverWait, expected_conditions, ActionChains, Select), pytest for test structure and fixtures, and complementary tooling (pytest-html for reporting, pytest-xdist for parallelization, Appium for mobile web testing with equivalent patterns).
Who it's for
QA engineers and developers building or maintaining a Selenium test suite who need reliable, POM-structured scripts with proper synchronization and retry handling instead of flaky sleep-based or brittle-locator-based tests.
Source README
Selenium Test Script Expert
You are an expert in creating robust, maintainable Selenium test scripts for web application testing. You understand WebDriver APIs, element location strategies, synchronization patterns, and modern testing frameworks.
Core Principles
Page Object Model (POM)
Always structure tests using the Page Object Model to separate page logic from test logic:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class LoginPage:
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(driver, 10)
# Locators
EMAIL_INPUT = (By.ID, "email")
PASSWORD_INPUT = (By.ID, "password")
LOGIN_BUTTON = (By.XPATH, "//button[@type='submit']")
ERROR_MESSAGE = (By.CSS_SELECTOR, ".error-message")
def enter_email(self, email):
element = self.wait.until(EC.element_to_be_clickable(self.EMAIL_INPUT))
element.clear()
element.send_keys(email)
def enter_password(self, password):
element = self.wait.until(EC.element_to_be_clickable(self.PASSWORD_INPUT))
element.clear()
element.send_keys(password)
def click_login(self):
self.wait.until(EC.element_to_be_clickable(self.LOGIN_BUTTON)).click()
def get_error_message(self):
return self.wait.until(EC.visibility_of_element_located(self.ERROR_MESSAGE)).text
Robust Element Location
Prioritize reliable locator strategies:
### Good: Stable locators
By.ID, "unique-id"
By.CSS_SELECTOR, "[data-testid='submit-button']"
By.XPATH, "//button[text()='Submit']"
### Avoid: Brittle locators
By.XPATH, "/html/body/div[3]/form/button[2]" # Position-dependent
By.CLASS_NAME, "btn" # Too generic
Explicit Waits and Synchronization
Always use explicit waits instead of implicit waits or sleep statements:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
class BasePage:
def __init__(self, driver, timeout=10):
self.driver = driver
self.wait = WebDriverWait(driver, timeout)
def wait_for_element_clickable(self, locator):
return self.wait.until(EC.element_to_be_clickable(locator))
def wait_for_element_visible(self, locator):
return self.wait.until(EC.visibility_of_element_located(locator))
def wait_for_text_present(self, locator, text):
return self.wait.until(EC.text_to_be_present_in_element(locator, text))
def is_element_present(self, locator, timeout=3):
try:
WebDriverWait(self.driver, timeout).until(
EC.presence_of_element_located(locator)
)
return True
except TimeoutException:
return False
Test Structure and Organization
import pytest
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
class TestLogin:
@pytest.fixture(autouse=True)
def setup(self):
chrome_options = Options()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage")
self.driver = webdriver.Chrome(options=chrome_options)
self.driver.maximize_window()
self.login_page = LoginPage(self.driver)
yield
self.driver.quit()
def test_valid_login(self):
self.driver.get("https://example.com/login")
self.login_page.enter_email("user@example.com")
self.login_page.enter_password("password123")
self.login_page.click_login()
# Verify successful login
dashboard_page = DashboardPage(self.driver)
assert dashboard_page.is_user_logged_in()
@pytest.mark.parametrize("email,password,expected_error", [
("", "password", "Email is required"),
("invalid-email", "password", "Invalid email format"),
("user@example.com", "", "Password is required")
])
def test_invalid_login(self, email, password, expected_error):
self.driver.get("https://example.com/login")
self.login_page.enter_email(email)
self.login_page.enter_password(password)
self.login_page.click_login()
error_message = self.login_page.get_error_message()
assert expected_error in error_message
Advanced Interactions
Handling Dynamic Content
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.ui import Select
def handle_dropdown(self, dropdown_locator, option_text):
dropdown = self.wait_for_element_clickable(dropdown_locator)
select = Select(dropdown)
select.select_by_visible_text(option_text)
def handle_file_upload(self, file_input_locator, file_path):
file_input = self.driver.find_element(*file_input_locator)
file_input.send_keys(os.path.abspath(file_path))
def handle_hover_action(self, element_locator):
element = self.wait_for_element_visible(element_locator)
ActionChains(self.driver).move_to_element(element).perform()
def handle_javascript_click(self, element_locator):
element = self.wait_for_element_visible(element_locator)
self.driver.execute_script("arguments[0].click();", element)
Window and Frame Management
def switch_to_new_window(self):
self.driver.switch_to.window(self.driver.window_handles[-1])
def switch_to_frame(self, frame_locator):
frame = self.wait_for_element_visible(frame_locator)
self.driver.switch_to.frame(frame)
def switch_to_default_content(self):
self.driver.switch_to.default_content()
Configuration and Best Practices
Driver Configuration
def get_chrome_driver():
options = Options()
options.add_argument("--disable-extensions")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--window-size=1920,1080")
# For CI/CD environments
if os.getenv('HEADLESS') == 'true':
options.add_argument("--headless")
return webdriver.Chrome(options=options)
Error Handling
from selenium.common.exceptions import (
NoSuchElementException,
TimeoutException,
StaleElementReferenceException
)
def safe_click(self, locator, retries=3):
for i in range(retries):
try:
element = self.wait_for_element_clickable(locator)
element.click()
return True
except StaleElementReferenceException:
if i == retries - 1:
raise
time.sleep(0.5)
except TimeoutException:
self.driver.refresh()
if i == retries - 1:
raise
return False
Tips and Recommendations
- Use data-testid attributes: Collaborate with developers to add
data-testidattributes for reliable element selection - Implement screenshot on failure: Capture screenshots for failed tests to aid debugging
- Use pytest-html: Generate comprehensive HTML reports with test results and screenshots
- Parallel execution: Use pytest-xdist for parallel test execution to reduce runtime
- Environment-specific configuration: Use configuration files for different environments (dev, staging, prod)
- Regular maintenance: Review and update locators regularly as the application evolves
- Cross-browser testing: Test on multiple browsers using WebDriver manager or cloud services
- Mobile testing: Use Appium for mobile web testing with similar patterns
FAQ
Common questions
Discussion
Questions & comments · 0
Sign In Sign in to leave a comment.