Page Best Practices¶
When using a Page class in your test automation framework, following best practices can significantly enhance the readability, maintainability, and effectiveness of your test code. Here are key best practices to consider when writing Page Objects:
1. Keep Page Classes Concise¶
A well-designed Page Object should be concise and focused on a specific page or component. Avoid making the page class overly lengthy, as this can hinder readability and make maintenance more challenging.
Recommendations¶
Limit Lines of Code: Strive to keep the page class manageable by limiting the number of lines. A concise page class is easier to read and understand.
Separate Concerns: If a page class becomes too large, consider breaking it down into smaller, more focused classes or components if the framework supports it.
2. Group Element Attributes¶
When a page contains many elements (more than 8-10), it is advisable to group them logically. This helps in organizing the code and improves readability.
Recommendations¶
Logical Grouping: Group elements based on their functionality or section of the page. For example, group footer controls, header controls, or form fields together.
Use Descriptive Names: Use clear and descriptive names for the groups and individual elements to enhance clarity.
Example¶
Here’s how you can organize a Page Object with a large number of elements by grouping them logically:
from mops.base.page import Page
from mops.base.element import Element
class DashboardPage(Page):
def __init__(self):
super().__init__(...)
# Footer Controls
footer_logout_button = Element('#footer-logout', name='Footer Logout Button')
footer_help_link = Element('#footer-help', name='Footer Help Link')
footer_contact_us = Element('#footer-contact', name='Footer Contact Us')
# Header Controls
header_notifications_icon = Element('#header-notifications', name='Header Notifications Icon')
header_user_profile = Element('#header-profile', name='Header User Profile')
header_search_box = Element('#header-search', name='Header Search Box')
# Main Content Controls
main_content_title = Element('#main-title', name='Main Content Title')
main_content_body = Element('#main-body', name='Main Content Body')
def navigate_to_settings(self):
"""
Navigate to the settings page.
"""
self.header_user_profile.click()
# Additional actions to navigate to settings
def is_dashboard_page_opened(self):
"""
Verify that the dashboard page is opened.
"""
return self.is_page_opened(with_elements=True, with_url=True)
DashboardPage().navigate_to_settings()
3. Split logic¶
When you have a large number of elements on a page, it is beneficial to group related elements into separate Group classes.
This not only makes the Page class cleaner but also allows for better organization of related elements and interactions.
Steps to Refactor¶
Identify Logical Groups:
Determine which elements are related and can be logically grouped together. For example, elements related to a form or a sidebar can be moved to their respective
Groupclasses.
Create
GroupClasses:Define new
Groupclasses to encapsulate these elements. EachGroupclass should inherit from a base class, similar toPage, and should initialize its elements.
Link Group Classes to the
PageClass:In the
Pageclass, add attributes that link to instances of theGroupclasses. This keeps thePageclass organized and provides access to the grouped elements.
Example¶
Below is an example demonstrating how to refactor a Page class by moving elements into separate Group classes:
from mops.base.page import Page
from mops.base.group import Group
from mops.base.element import Element
class Header(Group):
def __init__(self):
super().__init__(...)
notifications_icon = Element('#header-notifications', name='Header Notifications Icon')
user_profile_button = Element('#header-profile', name='Header User Profile')
search_box = Element('#header-search', name='Header Search Box')
def navigate_to_settings(self):
"""
Navigate to the settings page.
"""
self.user_profile_button.click()
class DashboardPage(Page):
def __init__(self):
super().__init__(...)
# Sections
header = Header()
# Footer Controls
footer_logout_button = Element('#footer-logout', name='Footer Logout Button')
footer_help_link = Element('#footer-help', name='Footer Help Link')
footer_contact_us = Element('#footer-contact', name='Footer Contact Us')
# Main Content Controls
main_content_title = Element('#main-title', name='Main Content Title')
main_content_body = Element('#main-body', name='Main Content Body')
def is_dashboard_page_opened(self):
"""
Verify that the dashboard page is opened.
"""
return self.is_page_opened(with_elements=True, with_url=True)
DashboardPage().header.navigate_to_settings()
# or
Header().navigate_to_settings()