Download address:/xiaopo1998/web_ui_test.git
Selenium Page Object Model Framework Instructions
This framework implements a modular and easy-to-maintain Page Object Model architecture based on Selenium WebDriver, separating different types of operations into different classes according to responsibilities.
Framework structure
The framework is designed in a layered manner and consists of the following main components:
core/
├── base_page.py # Basic page class, including access to core operation methods and other components
├── element_actions.py # element waiting and check operations
├── action_chains.py # Advanced Mouse and Keyboard Operations
├── browser_operations.py # window, frame and warning box operations
├── browser_utils.py # Cookie, JavaScript and screenshots and other auxiliary functions
├── select_operations.py # drop-down box specific operation
├── # WebDriver Management
└── # Log Management
Component Description
- BasePage (base_page.py)
The basic page class is the core of the entire framework, responsible for providing basic page operation methods and serving as an entry point for accessing other dedicated components. It contains the following core features:
Provide basic element search methods
Provide common element operation methods (click, enter, get text, etc.)
Responsible for instantiating and providing access to all dedicated components
2. ElementActions (element_actions.py)
Element waiting and check operation classes are specifically responsible for handling element visibility, existence and other inspection and wait operations. Main functions include:
Provide various elements waiting methods (waiting to be visible, waiting to be clickable, etc.)
Provide element status check method (whether it exists, is visible, etc.)
Provide text and attribute-related waiting methods
3. ActionChainOperations (action_chains.py)
The advanced operation class of mouse and keyboard, responsible for handling complex interactions. Main functions include:
Mouse operation (hover, drag and drop, right-click, etc.)
Keyboard operation (keys, key combinations, etc.)
Other advanced interactive operations
4. BrowserOperations (browser_operations.py)
The browser operation class is responsible for handling operations such as windows, frames and warning boxes. Main functions include:
Window operation (switch, close, get handle, etc.)
Frame operation (switch frames, return to main document, etc.)
Warning box operation (accept, cancel, get text, etc.)
Page navigation (forward, backward, refresh, etc.)
5. BrowserUtils (browser_utils.py)
Browser tool class, providing auxiliary functions such as cookie management, JavaScript execution and screenshots. Main functions include:
Cookie management (get, add, delete, etc.)
JavaScript execution (scrolling pages, etc.)
Screenshot function (full page screenshots, element screenshots, etc.)
6. SelectOperations (select_operations.py)
The drop-down box operation class is specially used to handle the operations of drop-down box elements. Main functions include:
Select options (by text, value, index, etc.)
Get selected option information
Multiple selection drop-down box operation (select multiple, deselect, etc.)
How to use
initialization
First, you need to initialize the BasePage object, which is the core entry point of the framework:
from selenium import webdriver
from core.base_page import BasePage
Initialize WebDriver
driver = ()
Create BasePage instance
page = BasePage(driver)
Navigate to page
page.navigate_to("")
Basic element operation
The BasePage class provides the most basic element operation method:
Define element locator
from import By
username_locator = (, "username")
password_locator = (, "password")
login_button_locator = (, "login")
Find elements
username_element = page.find_element(username_locator)
Basic element operation
page.input_text(username_locator, "test_user")
page.input_text(password_locator, "password123")
(login_button_locator)
Get element text
text = page.get_text((, "welcome_message"))
print(text)
Get element attributes
value = page.get_attribute((, "username"), "value")
Element waiting and checking
Access element waiting and check functions through element attribute:
Wait for the element to be visible
.wait_for_element_visible((, "dashboard"))
Check if the element exists
if .is_element_present((, "error_message")):
print("Login failed")
Wait for the text to appear
.wait_for_text_present((, "status"), "success")
Highlight elements (useful for debugging)
.highlight_element((By.LINK_TEXT, "User Settings"))
Waiting for the element to be invisible
.wait_for_element_not_visible((, "loading"))
Scroll to element position
.scroll_to_element((, "footer"))
Mouse and keyboard operation
Access the advanced mouse and keyboard actions through the actions property:
from import Keys
Mouse hover
.mouse_hover((, "menu"))
Right-click
.right_click((, "context_menu"))
double click
.double_click((, "double_click_element"))
Drag and drop operation
.drag_and_drop((, "source"), (, "target"))
Key operation
.press_key((, "search_box"), )
Key combination
.press_key_sequence((, "text_editor"), , "a")
Click and hold
.click_and_hold((, "slider"))
release
()
Move the mouse
.move_by_offset(10, 20)
Browser windows and framework operations
Access windows, frames, and warning boxes through browser properties:
Window Operation
original_handle = .get_current_window_handle()
.open_new_tab("/other_page")
.switch_to_window(window_index=0) # Switch back to the original window
.close_current_window()
Framework Operation
.switch_to_frame((, "iframe_id"))
.switch_to_default_content()
.switch_to_parent_frame()
Warning box operation
.accept_alert()
alert_text = .get_alert_text()
.dismiss_alert()
.send_text_to_alert("Input Content")
Navigation operations
.refresh_page()
.go_back()
.go_forward()
Get the page source code
html = .get_page_source()
Wait for the page to load
.wait_for_page_load()
Cookie and JavaScript Operations
Access cookies, JavaScript and screenshot functions through the utils attribute:
Cookie operation
cookies = .get_cookies()
cookie = .get_cookie("session_id")
.add_cookie({"name": "session", "value": "123456"})
.delete_cookie("old_cookie")
.delete_all_cookies()
JavaScript Operations
.scroll_to_top()
.scroll_to_bottom()
.scroll_by(0, 500) # Scroll down 500 pixels
screenshot
screenshot_path = .take_screenshot("login_page.png")
element_screenshot = .take_element_screenshot((, "error"), "")
Pull down box operation
Accessing the drop-down box special operation through the select property:
Select the drop-down box option
.select_by_text((, "country"), "China")
.select_by_value((, "country"), "CN")
.select_by_index((, "country"), 0)
Get the selected option
selected_text = .get_selected_text((, "country"))
selected_value = .get_selected_value((, "country"))
Get all options
all_options = .get_all_options((, "country"))
all_option_texts = .get_all_options_text((, "country"))
all_option_values = .get_all_options_value((, "country"))
Determine whether the drop-down box supports multiple selections
is_multiple = .is_multiple((, "multi_select"))
Multiple selection drop-down box operation
if .is_multiple((, "multi_select")):
.select_by_text((, "multi_select"), "Option 1")
.select_by_text((, "multi_select"), "Option 2")
.deselect_by_text((, "multi_select"), "Option 1")
.deselect_all((, "multi_select"))
Custom page class
In actual projects, it is recommended to create a subclass inherited from BasePage for each page:
from core.base_page import BasePage
from import By
class LoginPage(BasePage):
# Define page element locator
USERNAME_INPUT = (, "username")
PASSWORD_INPUT = (, "password")
LOGIN_BUTTON = (, "login")
ERROR_MESSAGE = (, "error")
def login(self, username, password):
"""
Login operation
:param username: Username
:param password: Password
"""
self.input_text(self.USERNAME_INPUT, username)
self.input_text(self.PASSWORD_INPUT, password)
(self.LOGIN_BUTTON)
def get_error_message(self):
"""
Get error message
:return: Error message text
"""
if .is_element_visible(self.ERROR_MESSAGE):
return self.get_text(self.ERROR_MESSAGE)
return None
def wait_for_login_success(self):
"""
Wait for login to succeed
"""
.wait_for_element_not_visible(self.ERROR_MESSAGE)
.wait_for_page_load()
Then you can use it like this:
Initialize the page
login_page = LoginPage(driver)
login_page.navigate_to("/login")
Perform login
login_page.login("user123", "password123")
Check results
error = login_page.get_error_message()
if error:
print(f"Login failed: {error}")
else:
print("Login successfully")
Best Practices
Organize code by page: Create a class inherited from BasePage for each page
Packaging business operations: encapsulating multiple basic operations into meaningful business methods
Use explicit wait: Always use the wait method to ensure elements are ready
Keep locators centrally defined in page classes: easy to maintain
Use the appropriate component: select the appropriate component according to the operation type (element, actions, browser, utils, select)
Use reasonable naming: method names and variable names should clearly indicate their role
Add detailed comments: Add comment instructions for complex operations
Handling exceptions: Catch and handle possible exceptions
Exception handling
Most methods in the framework log and throw exceptions (such as TimeoutException). It is recommended to catch these exceptions in the test code:
try:
((, "non_existent_button"))
except Exception as e:
print(f"Operation failed: {e}")
.take_screenshot("")
Extended framework
To add new features, you can extend an existing class or create a new operation class:
Extend the ElementActions class
from core.element_actions import ElementActions
from import WebDriverWait
class ExtendedElementActions(ElementActions):
def wait_for_element_count(self, locator, count, timeout=None):
"""
Wait for the number of elements to reach the expected value
:param locator: element locator
:param count: The expected number of elements
:param timeout: timeout
"""
timeout = timeout or ['browser']['implicit_wait']
(f"Waiting for the number of elements {locator} to reach {count}")
def check_count(driver):
elements = driver.find_elements(*locator)
return len(elements) == count
WebDriverWait(, timeout).until(check_count)
Frequently Asked Questions
The element cannot be found
Make sure to use the correct locator
Check if the element is visible in the page
Consider using the wait method to ensure that the element is loaded
The operation has no effect
Check if the element is blocked by other elements
Ensure elements are interactive
Try to perform an operation using JavaScript
Frame switching issues
After operating elements in the iframe, remember to switch back to the default content
Nested iframes need to be switched layer by layer
Multi-window operation
After switching to a new window, if you need to return to the original window, remember to save the handle of the original window
Note that the handle list will change after closing the window
Element selection problem
If a locator matches multiple elements, find_element returns the first matching element
More precise positioning strategies can be used or multiple positioning conditions can be combined
More examples
Form operation
Loading form page
page.navigate_to("/form")
Enter text
page.input_text((, "first_name"), "Zhang")
page.input_text((, "last_name"), "three")
Select the drop-down box
.select_by_text((, "country"), "China")
Select the radio button
((By.CSS_SELECTOR, "input[name='gender'][value='male']"))
Check the check box
((, "agreement"))
Submit a form
((By.CSS_SELECTOR, "button[type='submit']"))
Wait for the results
.wait_for_text_present((, "result"), "submit successful")
Table operations
Get all rows in the table
rows = page.find_elements((By.CSS_SELECTOR, "table tr"))
Traversal
for row in rows[1:]: # Skip the header
# Get the cell
cells = row.find_elements_by_tag_name("td")
if len(cells) > 0:
print(f"First column: {cells[0].text}, second column: {cells[1].text}")
# Click the button in the row
if len(cells) > 3:
edit_button = cells[3].find_element_by_tag_name("button")
edit_button.click()
break
File upload
import os
Upload file
file_path = ("./test_file.txt")
page.input_text((, "file_input"), file_path)
Click the Upload button
((, "upload_button"))
Wait for uploading to complete
.wait_for_text_present((, "upload_status"), "upload successful")
Test case example
Full login-search-purchase process
Here is a complete e-commerce website test case showing how to integrate all the knowledge points:
import unittest
from selenium import webdriver
from import TimeoutException
from pages.login_page import LoginPage
from pages.home_page import HomePage
from pages.product_page import ProductPage
from pages.cart_page import CartPage
from pages.checkout_page import CheckoutPage
import time
class ShoppingTest():
def setUp(self):
# Initialize WebDriver
= ()
.maximize_window()
# Initialize all page objects
self.login_page = LoginPage()
self.home_page = HomePage()
self.product_page = ProductPage()
self.cart_page = CartPage()
self.checkout_page = CheckoutPage()
def tearDown(self):
# Test ends, close the browser
if :
()
@screenshot_on_failure # Use the decorator defined earlier
def test_purchase_flow(self):
"""Test the complete purchase process"""
# Test data
username = "test_user"
password = "Test@123"
product_name = "Test product"
# 1. Log in
self.login_page.navigate_to("/login")
self.login_page.wait_for_page_load()
self.login_page.login(username, password)
# Verify login successfully
user_welcome = self.home_page.get_welcome_message()
(username, user_welcome, "The username does not appear after login")
# 2. Search for products
self.home_page.search_product(product_name)
# Verify search results
search_count = self.home_page.get_search_results_count()
(search_count, 0, "search no results")
# 3. Open product details
self.home_page.click_first_product()
# Verify product details page
product_title = self.product_page.get_product_title()
(product_name, product_title, f"Product details page does not match, expect to include '{product_name}'")
# 4. Add to cart
self.product_page.add_to_cart()
# 5. View the cart
self.product_page.go_to_cart()
# Verify the shopping cart
cart_items = self.cart_page.get_cart_items()
(len(cart_items), 1, "Car is empty")
# 6. Enter the checkout process
self.cart_page.proceed_to_checkout()
# 7. Fill in the receipt information
self.checkout_page.fill_shipping_info({
"name": "Zhang San",
"phone": "13800138000",
"address": "Six-six-six-street in Haidian District, Beijing",
"zipcode": "100000"
})
# 8. Select payment method
self.checkout_page.select_payment_method("cod") # cash on delivery
# 9. Submit an Order
order_number = self.checkout_page.place_order()
# Verify that the order is submitted successfully
success_message = self.checkout_page.get_success_message()
("Order has been submitted successfully", success_message)
(order_number, "Order number not generated")
# 10. Snap the screenshot of the successful page
self.checkout_page.utils.take_screenshot(f"order_success_{order_number}.png")
print(f"Test completed, order number: {order_number}")
if name == "main":
()