Skill

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.

Works with seleniumpytest

Maintainer of this project? Claim this page to edit the listing.


79
Spark score
out of 100
Updated 7 months ago
Version 1.0.0
Models

Add 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

01

Generate Selenium test scripts using Page Object Model.

02

Implement explicit waits for synchronization.

03

Utilize robust element location strategies.

04

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

  1. Use data-testid attributes: Collaborate with developers to add data-testid attributes for reliable element selection
  2. Implement screenshot on failure: Capture screenshots for failed tests to aid debugging
  3. Use pytest-html: Generate comprehensive HTML reports with test results and screenshots
  4. Parallel execution: Use pytest-xdist for parallel test execution to reduce runtime
  5. Environment-specific configuration: Use configuration files for different environments (dev, staging, prod)
  6. Regular maintenance: Review and update locators regularly as the application evolves
  7. Cross-browser testing: Test on multiple browsers using WebDriver manager or cloud services
  8. 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.