I'm looking for optimization between these files, and simplification. If something already exists to do what I have a keyword do, I'd like to know about it. Loops.py is located in one of my other posts (Python - Robot Framework Loops). o_o.py is down below. The idea behind this is to shorten the amount of code required to write Robot Framework commands and have universal waits after most actions (clears up a lot of timing issues before they start and can be set to 0 for speed).
*** Settings ***
Library ExtendedSelenium2Library
Library Collections
Library OperatingSystem
Library Loops.py
Library o_o.py
*** Variables ***
${ABS_PATH} C:/Users/user1/PycharmProjects
${BROWSER} chrome
${PROJECT} ProjectName
${SLOW_TIME} 0.5s
*** Keywords ***
Check and Cancel
# EXAMPLE USAGE
# Check and Cancel id=elementId blank Ok
# Check and Cancel id=firstId id=secondId
# NOTE: Make sure that if you're only clicking one element you put "blank" in the second cell.
[Arguments] ${click_one} ${click_two}='blank' ${cancel}='Cancel'
Click Element ${click_one}
Slow Down ${SLOW_TIME}
Run Keyword Unless '${click_two}'=='blank' Click Element ${click_two}
Run Keyword Unless '${click_two}'=='blank' Slow Down ${SLOW_TIME}
Click Button ${cancel}
Slow Down ${SLOW_TIME}
Click Dom List
# EXAMPLE USAGE
# Click Dom List "select" 1 "option"
# NOTE: Since this uses the dom, you may need to use the browser's console feature in order to find the index.
# NOTE: This allows injections on purpose for more advanced users
[Arguments] ${first_tag} ${first_index} ${second_tag}
${max_num}= Execute Javascript return document.getElementsByTagName(${first_tag})[${first_index}].getElementsByTagName(${second_tag}).length;
:FOR ${INDEX} IN RANGE 0 ${max_num}
\ Click Element dom=document.getElementsByTagName(${first_tag})[${first_index}].getElementsByTagName(${second_tag})[${INDEX}]
Click Dom Tag
# EXAMPLE USAGE
# Click Dom Tag "button" 1
# NOTE: Since this uses the dom, you may need to use the browser's console feature in order to find the index.
# NOTE: This allows injections on purpose for more advanced users
[Arguments] ${tag} ${index}
Click Element dom=document.getElementsByTagName(${tag})[${index}]
Click Element by Text
# EXAMPLE USAGE
# Click Element by Text "text on the element" id="midlevellocationoftext" button
# NOTE: Does not account for extra spaces at the beginning or end, text must be exact
# NOTE: Allows for injections on purpose to allow user to be more exact with their location
[Arguments] ${text} ${location}=* ${elementtype}=*
Click Element xpath=//*[@${location}]//${elementtype}[text()=${text}]
Click First HREF
# EXAMPLE USAGE
# Click First HREF hreftext
# NOTE: This clicks the first instance of the given HREF on the page
[Arguments] ${href}
Click Link ${href}
Dismiss Alert If Present
# EXAMPLE USAGE
# Dismiss Alert If Present
# NOTE: This keyword never fails
Run Keyword and Ignore Error Dismiss Alert
Dom Tag
# EXAMPLE USAGE
# ${usable_variable} = Dom Tag li 1
[Arguments] ${tag} ${index}
${dom} = Convert to String dom=document.getElementsByTagName(${tag})[${index}]
[Return] ${dom}
Open Chrome
# EXAMPLE USAGE
# Open Chrome www.google.com
[Arguments] ${HOMEPAGE}
${options} Evaluate sys.modules['selenium.webdriver'].ChromeOptions() sys
Call Method ${options} add_argument --start-maximized
Create WebDriver Chrome chrome_options=${options}
Go To ${HOMEPAGE}
Pause
# EXAMPLE USAGE
# Pause ${SLOW_TIME}
[Arguments] ${SLOW_TIME}
Slow Down ${SLOW_TIME}
Slow Down ${SLOW_TIME}
Slow Down ${SLOW_TIME}
Slow Down ${SLOW_TIME}
Reset Test Suite
# EXAMPLE USAGE
# REQUIREMENTS: Must have the local resource file imported first with ${HOMEPAGE} defined
# Reset Test Suite ${HOMEPAGE} ${BROWSER}
[Arguments] ${HOMEPAGE} ${BROWSER}
Close All Browsers
Register Keyword to Run on Failure Nothing
${chrome_check} = Run Keyword and Return Status Should Be Equal As Strings ${BROWSER} chrome
Run Keyword If ${chrome_check} Open Chrome ${HOMEPAGE}
Run Keyword Unless ${chrome_check} Open Browser ${HOMEPAGE} ${BROWSER}
Wait Until Keyword Succeeds 1 minute 0.01s Verify Location ${HOMEPAGE}
Slow Down
# EXAMPLE USAGE
# Slow Down ${SLOW_TIME}
[Arguments] ${SLOW_TIME}
Sleep ${SLOW_TIME}
Stop
# EXAMPLE USAGE
# Stop
Sleep 9999s
Suite Auto-Setup
# EXAMPLE USAGE
# REQUIREMENTS: Must have the local resource file imported first with ${HOMEPAGE} defined
# Suite Auto-Setup ${HOMEPAGE} ${BROWSER}
[Arguments] ${HOMEPAGE} ${BROWSER}
Register Keyword to Run on Failure Nothing
${chrome_check} = Run Keyword and Return Status Should Be Equal As Strings ${BROWSER} chrome
Run Keyword If ${chrome_check} Open Chrome ${HOMEPAGE}
Run Keyword Unless ${chrome_check} Open Browser ${HOMEPAGE} ${BROWSER}
Wait Until Keyword Succeeds 1 minute 0.01s Verify Location ${HOMEPAGE}
Suite Auto-Teardown
# EXAMPLE USAGE
# Suite Auto-Teardown
Log to Console Test Suite Complete
Log to Console ==============================================================================
Close All Browsers
Toggle
# EXAMPLE USAGE
# Toggle id=toggleElement
# Toggle id=dropdownId id=toggleElement
# NOTE: This can be used in any circumstance where you want to toggle an option in a dropdown list.
# NOTE: This can be used in any circumstance where you want to toggle two options simultaneously.
[Arguments] ${ele1} ${ele2}='blank'
Click Element ${ele1}
Slow Down ${SLOW_TIME}
Run Keyword Unless ${ele2}=='blank' Click Element ${ele2}
Run Keyword Unless ${ele2}=='blank' Slow Down ${SLOW_TIME}
Click Element ${ele1}
Slow Down ${SLOW_TIME}
Run Keyword Unless ${ele2}=='blank' Click Element ${ele2}
Run Keyword Unless ${ele2}=='blank' Slow Down ${SLOW_TIME}
Verify Element Is Ready
# EXAMPLE USAGE
# Verify Element Is Ready id=myElementId
# Click Element id=myElementId
# NOTE: Use before every single click.
[Arguments] ${element}
Variable should exist ${element}
Wait until element is visible ${element}
Element should be visible ${element}
Wait until element is enabled ${element}
Verify Location
# EXAMPLE USAGE
# Verify Location www.google.com
[Arguments] ${desired_url}
${current_url}= Get Location
Should Be Equal As Strings ${current_url} ${desired_url}
o_o.py
# robot.libraries.BuiltIn is needed to execute javascript
# pyautogui is what is used to click on screen coordinates after calculation
# so, "pip install robot" and "pip install pyautogui" are both needed before this script can run
from robot.libraries.BuiltIn import BuiltIn
import pyautogui as pag
class o_o(object):
"""
This class manages utilities for robot framework tests
Dependencies: robot, pyautogui
"""
def __init__(self):
# Instantiate ExtendedSelenium2Library
self.selenium_lib = BuiltIn().get_library_instance('ExtendedSelenium2Library')
def click_by_image(self, image_name):
"""
Click the center of a rectangle on the screen given the
image_name of the image rectangle to search for
:param image_name: Path to image
"""
pag.click(pag.locateCenterOnScreen(str(image_name)))
def click_by_locator(self, locator):
"""
Click the center of web element giv
:param locator: The locator for a web element conforming to Robot Framework
syntax.
See http://robotframework.org/ExtendedSelenium2Library/ExtendedSelenium2Library.html#Locating%20or%20specifying%20elements
"""
element_coordinates = self._get_element_screen_coordinates(str(locator))
pag.click(element_coordinates['x'], element_coordinates['y'])
def double_click_by_image(self, image_name):
"""
Double-click the center of a rectangle on the screen given the
image_name of the image rectangle to search for
:param image_name: Path to image
"""
pag.doubleClick(pag.locateCenterOnScreen(str(image_name)))
def _get_element_screen_coordinates(self, locator):
# Find coordinates of HTML element on the computer screen by
# factoring in the position of element in browser and the position
# of browser in screen.
# :param locator: The locator of the HTML element, ex: id=theId
# :return: HTML element coordinates relative to computer screen
gui_screen_size = pag.size()
javascript_screen_size = (self.selenium_lib.execute_javascript('return screen.width'),
self.selenium_lib.execute_javascript('return screen.height'))
screen_size_multiple = (gui_screen_size[0] / float(javascript_screen_size[0]),
gui_screen_size[1] / float(javascript_screen_size[1]))
browser_toolbar_height = 'window.outerHeight - window.innerHeight'
# Use screenX/screenY or screenLeft/screenTop based on browser support
window_position = {
'x': self.selenium_lib.execute_javascript('return window.screenX ? \
window.screenX : window.screenLeft'),
'y': self.selenium_lib.execute_javascript('return (window.screenY ? \
window.screenY : window.screenTop) + ' +
browser_toolbar_height)
}
element_position_on_browser = {
'x': self.selenium_lib.get_horizontal_position(str(locator)),
'y': self.selenium_lib.get_vertical_position(str(locator))
}
element_size = self.selenium_lib.get_element_size(str(locator))
return {
'x': (window_position['x'] + element_position_on_browser['x']
+ element_size[0]/2.0) * float(screen_size_multiple[0]),
'y': (window_position['y'] + element_position_on_browser['y']
+ element_size[1]/2.0) * float(screen_size_multiple[1])
}
Any advice/comments/criticism on readability, optimization, durability, portability, or usefulness (or lack thereof) is more than welcome. Again, some of these just make the Robot Framework code in the regular Resource files shorter.
As an additional note, if you happen to have the main resource called, you have automatic access to the libraries and resources that it calls.
'ExtendedSelenium2Library'
when initiating your class ? \$\endgroup\$__init__
is called just after the instantiation, you are (almost) sure thatself.selenium_lib
will never beNone
. Do you plan to useo_o
as ancestor to other classes (without callingsuper
, which would not be a traditional/good practice though) ? If not, you can simply removeif self.selenium_lib is None:
. \$\endgroup\$