poium一直我在維護的一個開源項目,它的定位是以極簡的方式在自動化項目中Page Objects設計模式。我在之前的文章中也有介紹。
本篇文章主要介紹一個JavaScript元素操作的封裝原理。
為什么要封裝JavaScript的API?
因為有些場景下Selenium提供的API並不能滿足我們需求。比如,滑動瀏覽滾動條,控制元素的顯示/隱藏,日歷控件的操作等,都可以通過JavaScrip實現,而且Selenium為我們提供了 execute_script()
方法可以用來運行JavaScrip腳本。
舊的設計思路
先看舊的設計代碼和調用。
# =====封裝代碼======
class Page(object):
def __init__(self, driver):
self.driver = driver
def set_text(self, css_selector, value):
"""
JavaScript API, Only support css positioning
Simulates typing into the element.
"""
js = """var elm = document.querySelector("{css}");
elm.style.border="2px solid red";
elm.value = "{value}";""".format(css=css_selector(), value=value)
self.driver.execute_script(js)
def click(self, css_selector):
"""
JavaScript API, Only support css positioning
Click element.
"""
js = """var elm = document.querySelector("{css}");
elm.style.border="2px solid red";
elm.click();""".format(css=css_selector())
self.driver.execute_script(js)
class CSSElement(object):
def __init__(self, css):
self.css = css
def __call__(self):
return self.css
# =======調用代碼==============
from selenium import webdriver
class baiduPage(Page):
search_input = CSSElement("#kw")
search_button = CSSElement("#su")
dr = webdriver.Chrome()
dr.get("http://www.baidu.com")
page = baiduPage(dr)
page.set_text(page.search_input, "poium")
page.click(page.search_button)
dr.close()
如果你看不懂上面的封裝代碼的話,可以重點看下面的調用代碼,針對元素的點擊和輸入。
page.set_text()
page.click()
表示操作的方法,在Page
類中實現。
page.search_input
page.search_button
表示操作的對象,在Page
的繼承類baiduPage
中定義。
page.set_text(page.search_input, "poium")
page.click(page.search_button)
操作的動作 和 操作的對象 都是以 page.
調用,萬一我要操作的對象也命名為 click
那不就和操作的動作 傻傻分不清楚了, 所以,這樣的語法不是很怪么?
所以,這個問題一直困擾我挺久的,我一直沒想到更好的設計。
新的設計思路
直到前幾天又重新學習了Python的 __get__
和 __set__
內置方法,才把這個問題解決。
# =====封裝代碼======
class Page(object):
def __init__(self, driver):
self.driver = driver
class CSSElement(object):
driver = None
def __init__(self, css):
self.css = css
def __get__(self, instance, owner):
if instance is None:
return None
global driver
driver = instance.driver
return self
def set_text(self, value):
global driver
driver.execute_script("""var elm = document.querySelector("{css}");
elm.style.border="2px solid red";
elm.value = "{value}";""".format(css=self.css, value=value))
def click(self):
global driver
driver.execute_script("""var elm = document.querySelector("{css}");
elm.style.border="2px solid red";
elm.click();""".format(css=self.css))
# =======調用代碼==============
from selenium import webdriver
class baiduPage(Page):
search_input = CSSElement("#kw")
search_button = CSSElement("#su")
dr = webdriver.Chrome()
dr.get("http://www.baidu.com")
page = baiduPage(dr)
page.search_input.set_text("poium")
page.search_button.click()
dr.close()
如果看不懂封裝代碼的話,直接看調用代碼。
page.search_input.set_text("poium")
page.search_button.click()
page
表示頁面; search_input
表示頁面上的某個對象; set_text()
表示對象的動作。
這樣的語法是不是要比前面好了很多?而保持了與Selenium API 封裝的語法一致性。
項目地址:https://github.com/defnngj/poium
做開源項目的生活就是這么朴實無華,且有趣!