Mastering Selenium for Efficient Automation Testing

by | Python

Installing and Setting Up Selenium with Python

Step 1: Install Python and Pip

Ensure Python and pip are installed on your system. Verify installation:

python --version
pip --version

Step 2: Install Selenium Library

Use pip to install the Selenium package.

pip install selenium

Step 3: Download WebDriver

Download the appropriate WebDriver (e.g., ChromeDriver for Chrome) from the official site https://sites.google.com/a/chromium.org/chromedriver/downloads.

Step 4: Write a Sample Script to Test Setup

Create a Python file, for example test_selenium.py, and add the following:

from selenium import webdriver

# Set path to the WebDriver
driver_path = '/path/to/chromedriver'

# Initialize WebDriver
driver = webdriver.Chrome(executable_path=driver_path)

# Open a website
driver.get('https://www.example.com')

# Close the browser
driver.quit()

Step 5: Run the Script

Execute the script:

python test_selenium.py

Summary

Install Python and pip.
Install the Selenium library using pip.
Download and set up the WebDriver.
Write and execute a sample Selenium script.

Navigating the Selenium WebDriver

# Import Selenium webdriver
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time

# Initialize the driver
driver = webdriver.Chrome()

# Open a webpage
driver.get("http://example.com")

# Find an element by ID and click it
element = driver.find_element(By.ID, "some_id")
element.click()

# Delay for observation
time.sleep(2)

# Find an element by name and send keys
element = driver.find_element(By.NAME, "some_name")
element.send_keys("text to send")

# Submit a form if the element is a form field
element.send_keys(Keys.RETURN)

# Delay for observation
time.sleep(2)

# Find an element by Xpath and retrieve text
element = driver.find_element(By.XPATH, "//tag[@attribute='value']")
element_text = element.text
print(f"Element Text: {element_text}")

# Delay for observation
time.sleep(2)

# Close the driver
driver.quit()

Ensure the necessary drivers and modules are correctly installed and configured. Apply valid identifiers for your specific use cases. Adjust time.sleep() for your timing needs.

Crafting Your First Test Script in Python

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import unittest

class GoogleSearchTest(unittest.TestCase):

    def setUp(self):
        # Initialize the WebDriver
        self.driver = webdriver.Chrome()

    def test_search_in_google(self):
        driver = self.driver
        driver.get("https://www.google.com")
        self.assertIn("Google", driver.title)
        
        # Locate the search box using its name attribute value
        search_box = driver.find_element(By.NAME, "q")
        search_box.clear()

        # Simulate typing 'Selenium' into the search box and pressing ENTER
        search_box.send_keys("Selenium")
        search_box.send_keys(Keys.RETURN)
        
        # Assert that results page is loaded
        self.assertTrue("No results found." not in driver.page_source)

    def tearDown(self):
        # Close the browser window
        self.driver.quit()

if __name__ == "__main__":
    unittest.main()

Utilizing Selenium Grid with Python

1. Setting Up Selenium Grid

Start the Hub

java -jar selenium-server-standalone-<version>.jar -role hub

Start a Node

java -jar selenium-server-standalone-<version>.jar -role node -hub http://localhost:4444/grid/register

2. Writing a Test Script using Selenium Grid

Import Libraries

from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

Define Remote WebDriver

# Configure WebDriver to connect to Selenium Grid (Hub)
grid_url = "http://localhost:4444/wd/hub"

# Define desired capabilities (Chrome example)
capabilities = DesiredCapabilities.CHROME

# Initialize the remote WebDriver
driver = webdriver.Remote(command_executor=grid_url, desired_capabilities=capabilities)

# Maximize browser window
driver.maximize_window()

Example Test Case

# Navigate to URL
driver.get("http://example.com")

# Perform actions (Replace with your test steps)
title = driver.title
assert "Example Domain" in title

# Close the browser
driver.quit()

Run the Test

Execute your Python script via CLI to run the Selenium Grid test.

python your_test_script.py

Example Full Script

from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

# Configure WebDriver to connect to Selenium Grid (Hub)
grid_url = "http://localhost:4444/wd/hub"
capabilities = DesiredCapabilities.CHROME

# Initialize the remote WebDriver
driver = webdriver.Remote(command_executor=grid_url, desired_capabilities=capabilities)

# Maximize the browser window
driver.maximize_window()

# Navigate to URL
driver.get("http://example.com")

# Perform actions
title = driver.title
assert "Example Domain" in title

# Close the browser
driver.quit()

This script assumes that the Selenium Grid hub and node are running and available at localhost:4444. Adjust DesiredCapabilities as needed for different browsers.

Creating Reusable Tests with Selenium IDE

Prerequisites

Ensure you have Selenium IDE installed as a browser extension and a basic understanding of how to use it.

Step-by-Step Guide

Step 1: Open Selenium IDE

Launch the Selenium IDE from your browser's extension toolbar.

Step 2: Creating a New Test Case

Create a New Project:

Name the project ReusableTestProject.

Define Test Case:

Create a test case named LoginTest.

Step 3: Recording the Login Test

Start Recording:

Click on the record button.

Perform Actions:

Navigate to your application login page.
Fill in the username and password.
Click the login button.

Stop Recording:

Click the stop button.

Save the Test Case:

Save the recorded steps under LoginTest.

Step 4: Creating Reusable Tests as Commands

Open Command Section:

Navigate to the command editor in Selenium IDE.

Define Reusable Commands for Steps:

Let's break down the login process into reusable steps.
{
  "id": "1",
  "type": "command",
  "name": "openApp",
  "description": "",
  "targets": [],
  "commands": [
    ["open", "/login"]
  ]
}

{
  "id": "2",
  "type": "command",
  "name": "typeCredentials",
  "description": "",
  "targets": [],
  "commands": [
    ["type", "id=username", "testuser"],
    ["type", "id=password", "password123"]
  ]
}

{
  "id": "3",
  "type": "command",
  "name": "clickLoginButton",
  "description": "",
  "targets": [],
  "commands": [
    ["click", "id=loginButton"]
  ]
}

Step 5: Using Reusable Commands in Test Cases

Modify LoginTest to use these commands:

Open the LoginTest.

Edit the Test Case Commands:

Replace the recorded login steps with reusable commands.
{
  "id": "LoginTest",
  "name": "LoginTest",
  "commands": [
    ["openApp"],
    ["typeCredentials"],
    ["clickLoginButton"]
  ]
}

Step 6: Extract and Use in Multiple Tests

Create Another Test Case:

Name the new test LogoutTest.

Record or Define Reusable Steps for Logout:

Follow similar steps for defining LogoutTest by splitting reusable steps.
{
  "id": "LogoutTest",
  "name": "LogoutTest",
  "commands": [
    ["openApp"],
    ["typeCredentials"],
    ["clickLoginButton"],
    ["click", "id=logoutButton"]
  ]
}

Final Check

  1. Run All Tests:
    • Ensure to run all tests in the suite to validate functionality.

Conclusion

Using the above steps, you have created reusable test steps using Selenium IDE and applied them across multiple test cases. This method ensures that your automation scripts are DRY (Don't Repeat Yourself) and maintainable.


Note: This implementation is using the JSON representation for Selenium IDE commands, which can be imported directly into the IDE for execution.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

# Initialize WebDriver
driver = webdriver.Chrome()

# Open a web page
driver.get("https://example.com")

# Wait for an element to be present
wait = WebDriverWait(driver, 10)
element = wait.until(EC.presence_of_element_located((By.ID, 'some_element_id')))

# Interact with web elements
element.click()
text_input = driver.find_element(By.NAME, 'some_input_name')
text_input.send_keys("Sample text")
button = driver.find_element(By.XPATH, '//button[text()="Submit"]')
button.click()

# Handle alerts
try:
    alert = WebDriverWait(driver, 3).until(EC.alert_is_present())
    alert.accept()
except:
    print("No alert present")

# Handle iframes
driver.switch_to.frame("iframe_name_or_id") 
iframe_element = driver.find_element(By.TAG_NAME, 'p')
print(iframe_element.text)
driver.switch_to.default_content()

# Scroll to an element
element_to_scroll = driver.find_element(By.ID, 'scroll_target')
driver.execute_script("arguments[0].scrollIntoView();", element_to_scroll)

# Handle dropdowns
from selenium.webdriver.support.ui import Select
select = Select(driver.find_element(By.ID, 'dropdown_id'))
select.select_by_visible_text('Option Text')

# Drag and drop
source_element = driver.find_element(By.ID, 'draggable')
target_element = driver.find_element(By.ID, 'droppable')
from selenium.webdriver import ActionChains
actions = ActionChains(driver)
actions.drag_and_drop(source_element, target_element).perform()

# Hover over an element to trigger an event
hover_element = driver.find_element(By.CLASS_NAME, 'hover_target')
actions.move_to_element(hover_element).perform()

# Performing composite actions
actions.click(driver.find_element(By.ID, 'action_target')). \
    send_keys('composite action key input'). \
    perform()

# Close the browser
driver.quit()
  • Initialize the WebDriver for Chrome.
  • Open the webpage.
  • Wait for the element to be present.
  • Interact with various web elements like buttons and text inputs.
  • Handle JavaScript alerts.
  • Switch to and from iframes.
  • Scroll to the desired element.
  • Handle dropdowns.
  • Perform drag and drop actions.
  • Hover over elements.
  • Execute composite actions.
  • Close the browser.

Implementing Waits and Synchronization in Selenium Tests with Python

Here is the code implementation for handling waits and synchronization in Selenium tests using Python:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

# Initialize WebDriver
driver = webdriver.Chrome()

try:
    # Navigate to the target website
    driver.get("http://example.com")

    # Implicit Wait - Applies to all elements for the entire duration of the WebDriver instance
    driver.implicitly_wait(10)  # Wait for up to 10 seconds for elements to be found

    # Explicit Wait - Applies to specific elements
    wait = WebDriverWait(driver, 20)  # Wait up to 20 seconds for the specified condition to be met

    # Example of explicit wait for an element to be clickable
    element = wait.until(EC.element_to_be_clickable((By.ID, "submit-button")))
    element.click()

    # Example of explicit wait for an element to be visible
    element = wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "target-div")))
    print(element.text)

    # Pause execution for a fixed amount of time (useful in specific cases but not recommended regularly)
    time.sleep(2)  # Sleep for 2 seconds

finally:
    # Cleanup - Close the WebDriver instance
    driver.quit()

This practical implementation allows you to efficiently handle waits and synchronization using both implicit and explicit waits.

Debugging and Optimizing Test Scripts

1. Debugging Test Scripts

Step 1: Increase Logging

import logging

logging.basicConfig(level=logging.INFO)

def test_login(driver, username, password):
    logging.info("Navigating to login page")
    driver.get('https://example.com/login')
    
    logging.info("Finding username and password fields")
    username_field = driver.find_element_by_name('username')
    password_field = driver.find_element_by_name('password')
    
    logging.info(f"Entering username: {username}")
    username_field.send_keys(username)
    
    logging.info(f"Entering password: {password}")
    password_field.send_keys(password)
    
    logging.info("Submitting form")
    driver.find_element_by_name('login').click()

    assert "Welcome" in driver.page_source
    logging.info("Login test passed")

Step 2: Adding Screen Shots on Failure

def capture_screenshot_on_failure(driver, test_func):
    try:
        test_func(driver)
    except Exception as e:
        driver.save_screenshot('screenshot.png')
        logging.error(f"Test failed: {e}")
        raise

# Example usage:
# capture_screenshot_on_failure(driver, test_login)

Step 3: Using Breakpoints for Step-by-Step Execution

import pdb

def test_example(driver):
    driver.get('https://example.com')
    pdb.set_trace()
    element = driver.find_element_by_id('example')
    element.click()
    assert "Expected Text" in driver.page_source

2. Optimizing Test Scripts

Step 1: Utilize Explicit Waits

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def test_with_explicit_wait(driver):
    driver.get('https://example.com')
    
    wait = WebDriverWait(driver, 10)
    element = wait.until(EC.presence_of_element_located((By.ID, 'example')))
    
    element.click()
    assert "Expected Text" in driver.page_source

Step 2: Refactor Repeated Code into Functions

def find_and_fill(driver, element_name, text):
    element = driver.find_element_by_name(element_name)
    element.send_keys(text)

def test_optimized_login(driver, username, password):
    driver.get('https://example.com/login')
    
    find_and_fill(driver, 'username', username)
    find_and_fill(driver, 'password', password)
    
    driver.find_element_by_name('login').click()
    assert "Welcome" in driver.page_source

Step 3: Run Tests in Parallel

from multiprocessing import Pool

def run_test(test_func):
    driver = webdriver.Chrome()
    test_func(driver)
    driver.quit()

if __name__ == "__main__":
    tests = [test_login1, test_login2, test_login3]
    with Pool(processes=len(tests)) as pool:
        pool.map(run_test, tests)

This setup boosts efficiency during selenium testing efforts by simplifying and enhancing code manageability and reliability.

Related Posts