SlideShare a Scribd company logo
PyUIA 0.3
Jeremy Kao / KKBOX SQA / Jun 23, 2015
Agenda
● Single Keyword Library
● Current Page Tracking
● UI Mapping, Page Factory Pattern and
Caching
● Handlers Rotation and API Changes
● Q&A
Abstraction of Layers
Single Keyword Library
As of v0.3 Prior to v0.3
Less Keyword Conflicts
Multiple keywords with name 'Do Something' found.
Give the full name of the keyword you want to use.
Found: 'ThatPage.Do Something' and 'ThisPage.Do Something'
Prior to PyUIA 0.3 - Multiple Libraries
class ThisPage(MyAppLibrary):
_page_class_ios = myapp.ios.ThisPage
_page_class_android = myapp.android.ThatPage
def should_be_on_this_page(self):
self._page_object.wait_for_page_loaded()
def do_something(self):
self._page_object.do_something(target)
class ThatPage(MyAppLibrary):
_page_class_ios = myapp.ios.ThatPage
_page_class_android = myapp.android.ThatPage
def should_be_on_that_page(self):
self._page_object.wait_for_page_loaded()
def do_something(self):
self._page_object.do_something(target)
As of PyUIA 0.3 - Single Library
class MyApp(BaseAppLibrary):
_page_class_ios = ios.ThisPage
_page_class_android = android.ThisPage
def do_something(self):
# for all pages that implement this operation/protocol.
self._page_object.do_something()
return self._current_page.do_something() # return the next page
Bootstrap - Wait For <INIT> Page
class MyApp(BaseAppLibrary):
def wait_for_welcome_page(self):
context = self._current_context
if context.platform == 'android':
from myapp.android import WelcomePage
else:
from myapp.ios import WelcomePage
return get_page_object(WelcomePage, context).wait_for_page_loaded()
Current Page Tracking
● this._current_page always points
to current page (of the current
device).
● PyUIA updates the current page
when a keyword returns a page
object.
● The current page determines the
runtime behavior of a keyword.
Thanks to Chloe Chen for the idea.
Current Page == Implicit Subject
Current page is an analogue to the implied subject in an
imperative sentence.
# Keywords
Wait For Home Page
Go To Settings
Enable Synchronization
Go Back
# Page Objects (Python)
home = HomePage(driver).
wait_for_page_loaded()
settings = home.go_to_settings()
settings.enable_synchronization()
settings.go_back() # Home
PageFactory Impl. in Python?
Refer to PageFactory (Java)...
● PageFactory implementation from selenium for python - Stack Overflow
(Nov 8, 2013)
● Does Webdriver support pagefactory for Python? - Stack Overflow (Dec
12, 2012)
● PageFactory Implementation in Python - Google Groups (May 8, 2012)
● PageFactory implementation in Python? - Google Groups (Aug 11, 2011)
Unfortunately, we have to invent the wheel ~ Implementing
PageFactory Pattern in Python (June 10, 2015) (find_by,
@cacheable)
Google Search Page
from pyuia.selenium import SeleniumPageObject as PageObject, find_by, cacheable
from selenium.webdriver.common.by.By
class GoogleSearchPage(PageObject):
_search_box = find_by(how=By.NAME, using='q')
_search_button = find_by(name='btnK')
def search(self, keywords):
self._search_box().click()
self._search_box().send_keys(keywords) # look up twice?
self._search_button().click()
The following keyword arguments are supported for various locator strategies: id_ (to avoid conflict
with the built-in keyword id), name, class_name, css_selector, tag_name, xpath, link_text,
partial_link_text.
find_by
def find_by(how=None, using=None, multiple=False, cacheable=True, if_exists=False,
context=None, driver_attr='_driver', **kwargs):
● multiple – the answer to @FindBy for a list of elements.
● cacheable – the answer to @CacheLookup. (see also
@cacheable for customized lookup.)
● if_exists - for conditional UI elements.
● context – the answer to @FindBys.
● driver_attr – the attribute name for getting the
reference to WebDriver. Defaults to ’_driver’.
find_by (cont.)
# prior to v0.3
def _clickme_button(self):
return self._driver.find_element_by_name('Click Me!')
def _clickme_button(self):
return self._driver.find_element_by_id('click_me')
# as of v0.3
_clickme_button = find_by(name='Click Me!')
_clickme_button = find_by(id_='click_me')
find_by (cont.)
# prior to v0.3
def _products(self):
container = self._driver.find_element_by_id('products_list')
return container.find_elements_by_class_name('android.widget.TextView')
# as of v0.3
_products = find_by(class_name='android.widget.TextView', multiple=True,
context=find_by(id_='products_list'))
find_by (cont.)
# prior to v0.3
def _tip_if_exists(self):
try:
return self._driver_find_element_by_id('tip')
except NoSuchElementException:
return None
# as of v0.3
_tip_if_exists = find_by(id_='tip', if_exists=True)
@cacheable (for customized lookup)
@cacheable
def _categories(self):
candidates = self._driver.find_elements_by_id('list')
assert len(candidates) == 2, candidates
container = candidates[1] # the 2nd one
return container.find_elements_by_class_name('android.widget.TextView')
Handlers Rotation
def assert_on_this_page(self):
self._assert_any_present(
[self._lyrics_button, self._discovery_tutorial_view_if_exists],
handlers={
self._other_device_playing_alert: self._dismiss_devices_alert, # H1
self._storage_space_alert: self._dismiss_storage_alert, # H2
self._high_quality_prompt_message: self._dismiss_high_quality_prompt # H3
})
# ...
● Prior to v0.3 - (H1 ➔ H2 ➔ H3) ➥ (H1 ➔ H2 ➔ H3) ...
● As of v0.3 - H1 ➥ H2 ➥ H3 ➥ H1 ➥ H3 ➥ H1 ➥ H1 ...
Modeling: Page and UI Fragment
MainPage
M
e
n
u
ActionBar
class Menu(class):
def open_menu(self): pass
class ActionBar(class):
def title(self): pass
class MainPage(AppiumPO, Menu, ActionBar): pass
Page-to-page Transitions
A(WelcomePage)
_go_to(page_class)
_back_to(page_class)
B(MainPage)
● assert_on_this_page(from_page_class) - assertion, no waiting
● _get_page_entry_handlers(from_page_class) - rotation
● _on_page_entry(from_page_class) - replace _wait_for_idle.
Page-to-page Transitions (cont.)
# Page A
_clickme_button = find_by(id_='click_me')
def go_to_b(self):
self._clickme_button().click()
return self._go_to(BPage)
# Page B
_back_button = find_by(name='Back')
def go_back(self):
self._back_button().click()
# go to the previous page by default
return self._back_to()
_go_to(page_class)
_back_to(page_class=None)
Page-to-page Transitions (cont.)
# WelcomePage
def assert_on_this_page(self, from_page_class):
self._assert_present(self._start_button)
def start(self):
self._start_button().click() # look up again?
self._go_to(MainPage)
Page-to-page Transitions (cont.)
# MainPage
def assert_on_this_page(self, from_page_class):
self._assert_present(self._main_menu)
def _get_page_entry_handlers(self, from_page_class):
if from_page_class == WelcomePage:
return { self._network_error: self._retry }
Page-to-page Transitions (cont.)
# MainPage
def _on_page_entry(self, from_page_class):
if from_page_class != WelcomePage: return
self._wait_disappear(self._loading_indicator)
self._watch({
self._chromecast_ok_button: self._dismiss_chromecast_tip,
self._tutorial_ok_button: self._dismiss_tutorial,
}, 10) # max duration
return True # indicates UI changed (takes another screenshot)
Where _watch (handlers, max_duration) replaces _handle_conditional_views
(handlers, duration)
References
● PyUIA
● Page Object Pattern (Martin Fowler)
● PageFactory pattern (Python impl.)
● 利用 Appium + Robot Framework 實現跨平
台 App 互動測試 (Nov 14, 2014)
Q&A
Thanks you all for listening ~

More Related Content

PDF
WinAppDriver Development
PDF
WinAppDriver - Windows Store Apps Test Automation
PPTX
ATAGTR2017 Upgrading a mobile tester's weapons with advanced debugging
PDF
Design Patterns in XCUITest
PPTX
Breaking free from static abuse in test automation frameworks and using Sprin...
PPTX
Write Selenide in Python 15 min
PDF
Page object pattern
PDF
Easy automation.py
WinAppDriver Development
WinAppDriver - Windows Store Apps Test Automation
ATAGTR2017 Upgrading a mobile tester's weapons with advanced debugging
Design Patterns in XCUITest
Breaking free from static abuse in test automation frameworks and using Sprin...
Write Selenide in Python 15 min
Page object pattern
Easy automation.py

What's hot (20)

PDF
Workshop 15: Ionic framework
PDF
How to React Native
PDF
Beyond Domino Designer
PPTX
Building Large Scale PHP Web Applications with Laravel 4
PDF
Modular Test-driven SPAs with Spring and AngularJS
PDF
Leave your jQuery behind
PDF
React Native: React Meetup 3
PDF
Test-Driven Documentation for your REST(ful) service
PPT
DJango
PDF
Android stepbystep
PDF
Automation Testing using Selenium Webdriver
PDF
Philip Shurpik "Architecting React Native app"
PDF
Android L01 - Warm Up
PPSX
Evolving an Application Architecture
PDF
Introduction to React Native
PDF
Testing iOS10 Apps with Appium and its new XCUITest backend
PPTX
An overview of selenium webdriver
PDF
Tellurium At Rich Web Experience2009
PDF
Pieter De Baets - An introduction to React Native
PPTX
Javascript Best Practices and Intro to Titanium
Workshop 15: Ionic framework
How to React Native
Beyond Domino Designer
Building Large Scale PHP Web Applications with Laravel 4
Modular Test-driven SPAs with Spring and AngularJS
Leave your jQuery behind
React Native: React Meetup 3
Test-Driven Documentation for your REST(ful) service
DJango
Android stepbystep
Automation Testing using Selenium Webdriver
Philip Shurpik "Architecting React Native app"
Android L01 - Warm Up
Evolving an Application Architecture
Introduction to React Native
Testing iOS10 Apps with Appium and its new XCUITest backend
An overview of selenium webdriver
Tellurium At Rich Web Experience2009
Pieter De Baets - An introduction to React Native
Javascript Best Practices and Intro to Titanium
Ad

Similar to PyUIA 0.3 (20)

PDF
Django design-patterns
PDF
Django class based views
PPTX
WordPress plugin #3
PDF
Art & music vs Google App Engine
PDF
OSCON Google App Engine Codelab - July 2010
PPTX
WordPress plugin #2
PPTX
End-to-end testing with geb
PDF
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
KEY
PyCon US 2012 - State of WSGI 2
PDF
Zyncro zyncro apps & ui customization feb 2013
PPTX
Making Magento flying like a rocket! (A set of valuable tips for developers)
PDF
Design Patterns in Automation Framework.pdf
PPTX
Web driver training
ODP
CodeIgniter PHP MVC Framework
PDF
Django Heresies
PDF
A Related Matter: Optimizing your webapp by using django-debug-toolbar, selec...
PDF
How to disassemble one monster app into an ecosystem of 30
PDF
Python magicmethods
PDF
Automating Django Functional Tests Using Selenium on Cloud
PDF
Using Task Queues and D3.js to build an analytics product on App Engine
Django design-patterns
Django class based views
WordPress plugin #3
Art & music vs Google App Engine
OSCON Google App Engine Codelab - July 2010
WordPress plugin #2
End-to-end testing with geb
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
PyCon US 2012 - State of WSGI 2
Zyncro zyncro apps & ui customization feb 2013
Making Magento flying like a rocket! (A set of valuable tips for developers)
Design Patterns in Automation Framework.pdf
Web driver training
CodeIgniter PHP MVC Framework
Django Heresies
A Related Matter: Optimizing your webapp by using django-debug-toolbar, selec...
How to disassemble one monster app into an ecosystem of 30
Python magicmethods
Automating Django Functional Tests Using Selenium on Cloud
Using Task Queues and D3.js to build an analytics product on App Engine
Ad

Recently uploaded (20)

PDF
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
PPTX
ai tools demonstartion for schools and inter college
PDF
How Creative Agencies Leverage Project Management Software.pdf
PDF
Softaken Excel to vCard Converter Software.pdf
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PPTX
history of c programming in notes for students .pptx
PPTX
CHAPTER 2 - PM Management and IT Context
PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PDF
Understanding Forklifts - TECH EHS Solution
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PPTX
Reimagine Home Health with the Power of Agentic AI​
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
ai tools demonstartion for schools and inter college
How Creative Agencies Leverage Project Management Software.pdf
Softaken Excel to vCard Converter Software.pdf
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
history of c programming in notes for students .pptx
CHAPTER 2 - PM Management and IT Context
Operating system designcfffgfgggggggvggggggggg
Upgrade and Innovation Strategies for SAP ERP Customers
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
Which alternative to Crystal Reports is best for small or large businesses.pdf
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
wealthsignaloriginal-com-DS-text-... (1).pdf
Understanding Forklifts - TECH EHS Solution
How to Migrate SBCGlobal Email to Yahoo Easily
Reimagine Home Health with the Power of Agentic AI​
Wondershare Filmora 15 Crack With Activation Key [2025

PyUIA 0.3

  • 1. PyUIA 0.3 Jeremy Kao / KKBOX SQA / Jun 23, 2015
  • 2. Agenda ● Single Keyword Library ● Current Page Tracking ● UI Mapping, Page Factory Pattern and Caching ● Handlers Rotation and API Changes ● Q&A
  • 4. Single Keyword Library As of v0.3 Prior to v0.3
  • 5. Less Keyword Conflicts Multiple keywords with name 'Do Something' found. Give the full name of the keyword you want to use. Found: 'ThatPage.Do Something' and 'ThisPage.Do Something'
  • 6. Prior to PyUIA 0.3 - Multiple Libraries class ThisPage(MyAppLibrary): _page_class_ios = myapp.ios.ThisPage _page_class_android = myapp.android.ThatPage def should_be_on_this_page(self): self._page_object.wait_for_page_loaded() def do_something(self): self._page_object.do_something(target) class ThatPage(MyAppLibrary): _page_class_ios = myapp.ios.ThatPage _page_class_android = myapp.android.ThatPage def should_be_on_that_page(self): self._page_object.wait_for_page_loaded() def do_something(self): self._page_object.do_something(target)
  • 7. As of PyUIA 0.3 - Single Library class MyApp(BaseAppLibrary): _page_class_ios = ios.ThisPage _page_class_android = android.ThisPage def do_something(self): # for all pages that implement this operation/protocol. self._page_object.do_something() return self._current_page.do_something() # return the next page
  • 8. Bootstrap - Wait For <INIT> Page class MyApp(BaseAppLibrary): def wait_for_welcome_page(self): context = self._current_context if context.platform == 'android': from myapp.android import WelcomePage else: from myapp.ios import WelcomePage return get_page_object(WelcomePage, context).wait_for_page_loaded()
  • 9. Current Page Tracking ● this._current_page always points to current page (of the current device). ● PyUIA updates the current page when a keyword returns a page object. ● The current page determines the runtime behavior of a keyword. Thanks to Chloe Chen for the idea.
  • 10. Current Page == Implicit Subject Current page is an analogue to the implied subject in an imperative sentence. # Keywords Wait For Home Page Go To Settings Enable Synchronization Go Back # Page Objects (Python) home = HomePage(driver). wait_for_page_loaded() settings = home.go_to_settings() settings.enable_synchronization() settings.go_back() # Home
  • 11. PageFactory Impl. in Python? Refer to PageFactory (Java)... ● PageFactory implementation from selenium for python - Stack Overflow (Nov 8, 2013) ● Does Webdriver support pagefactory for Python? - Stack Overflow (Dec 12, 2012) ● PageFactory Implementation in Python - Google Groups (May 8, 2012) ● PageFactory implementation in Python? - Google Groups (Aug 11, 2011) Unfortunately, we have to invent the wheel ~ Implementing PageFactory Pattern in Python (June 10, 2015) (find_by, @cacheable)
  • 12. Google Search Page from pyuia.selenium import SeleniumPageObject as PageObject, find_by, cacheable from selenium.webdriver.common.by.By class GoogleSearchPage(PageObject): _search_box = find_by(how=By.NAME, using='q') _search_button = find_by(name='btnK') def search(self, keywords): self._search_box().click() self._search_box().send_keys(keywords) # look up twice? self._search_button().click() The following keyword arguments are supported for various locator strategies: id_ (to avoid conflict with the built-in keyword id), name, class_name, css_selector, tag_name, xpath, link_text, partial_link_text.
  • 13. find_by def find_by(how=None, using=None, multiple=False, cacheable=True, if_exists=False, context=None, driver_attr='_driver', **kwargs): ● multiple – the answer to @FindBy for a list of elements. ● cacheable – the answer to @CacheLookup. (see also @cacheable for customized lookup.) ● if_exists - for conditional UI elements. ● context – the answer to @FindBys. ● driver_attr – the attribute name for getting the reference to WebDriver. Defaults to ’_driver’.
  • 14. find_by (cont.) # prior to v0.3 def _clickme_button(self): return self._driver.find_element_by_name('Click Me!') def _clickme_button(self): return self._driver.find_element_by_id('click_me') # as of v0.3 _clickme_button = find_by(name='Click Me!') _clickme_button = find_by(id_='click_me')
  • 15. find_by (cont.) # prior to v0.3 def _products(self): container = self._driver.find_element_by_id('products_list') return container.find_elements_by_class_name('android.widget.TextView') # as of v0.3 _products = find_by(class_name='android.widget.TextView', multiple=True, context=find_by(id_='products_list'))
  • 16. find_by (cont.) # prior to v0.3 def _tip_if_exists(self): try: return self._driver_find_element_by_id('tip') except NoSuchElementException: return None # as of v0.3 _tip_if_exists = find_by(id_='tip', if_exists=True)
  • 17. @cacheable (for customized lookup) @cacheable def _categories(self): candidates = self._driver.find_elements_by_id('list') assert len(candidates) == 2, candidates container = candidates[1] # the 2nd one return container.find_elements_by_class_name('android.widget.TextView')
  • 18. Handlers Rotation def assert_on_this_page(self): self._assert_any_present( [self._lyrics_button, self._discovery_tutorial_view_if_exists], handlers={ self._other_device_playing_alert: self._dismiss_devices_alert, # H1 self._storage_space_alert: self._dismiss_storage_alert, # H2 self._high_quality_prompt_message: self._dismiss_high_quality_prompt # H3 }) # ... ● Prior to v0.3 - (H1 ➔ H2 ➔ H3) ➥ (H1 ➔ H2 ➔ H3) ... ● As of v0.3 - H1 ➥ H2 ➥ H3 ➥ H1 ➥ H3 ➥ H1 ➥ H1 ...
  • 19. Modeling: Page and UI Fragment MainPage M e n u ActionBar class Menu(class): def open_menu(self): pass class ActionBar(class): def title(self): pass class MainPage(AppiumPO, Menu, ActionBar): pass
  • 20. Page-to-page Transitions A(WelcomePage) _go_to(page_class) _back_to(page_class) B(MainPage) ● assert_on_this_page(from_page_class) - assertion, no waiting ● _get_page_entry_handlers(from_page_class) - rotation ● _on_page_entry(from_page_class) - replace _wait_for_idle.
  • 21. Page-to-page Transitions (cont.) # Page A _clickme_button = find_by(id_='click_me') def go_to_b(self): self._clickme_button().click() return self._go_to(BPage) # Page B _back_button = find_by(name='Back') def go_back(self): self._back_button().click() # go to the previous page by default return self._back_to() _go_to(page_class) _back_to(page_class=None)
  • 22. Page-to-page Transitions (cont.) # WelcomePage def assert_on_this_page(self, from_page_class): self._assert_present(self._start_button) def start(self): self._start_button().click() # look up again? self._go_to(MainPage)
  • 23. Page-to-page Transitions (cont.) # MainPage def assert_on_this_page(self, from_page_class): self._assert_present(self._main_menu) def _get_page_entry_handlers(self, from_page_class): if from_page_class == WelcomePage: return { self._network_error: self._retry }
  • 24. Page-to-page Transitions (cont.) # MainPage def _on_page_entry(self, from_page_class): if from_page_class != WelcomePage: return self._wait_disappear(self._loading_indicator) self._watch({ self._chromecast_ok_button: self._dismiss_chromecast_tip, self._tutorial_ok_button: self._dismiss_tutorial, }, 10) # max duration return True # indicates UI changed (takes another screenshot) Where _watch (handlers, max_duration) replaces _handle_conditional_views (handlers, duration)
  • 25. References ● PyUIA ● Page Object Pattern (Martin Fowler) ● PageFactory pattern (Python impl.) ● 利用 Appium + Robot Framework 實現跨平 台 App 互動測試 (Nov 14, 2014)
  • 26. Q&A Thanks you all for listening ~