webdriver支持显式和隐式的同步。本节主要内容如下:
-
显式和隐式等待
-
何时使用显式和隐式的等待
-
使用预期条件
-
创建自定义的等待状态
使用隐式等待
隐式等待提供了通用的方法同步测试和步骤。适用于网络响应时间不一致或者使用Ajax调用渲染元素的时候。
隐式等待的默认超时时间是0,对整个webdriver生效。这个功能我们在第2章就有使用,现在我们把当时实例的隐式等待时间从30秒改成10秒。
import unittest
from selenium import webdriver
class SearchProductTest(unittest.TestCase):
def setUp(self):
# create a new Firefox session
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(10)
self.driver.maximize_window()
# navigate to the application home page
self.driver.get('http://demo-store.seleniumacademy.com/')
def test_search_by_category(self):
# get the search textbox
self.search_field = self.driver.find_element_by_name('q')
self.search_field.clear()
# enter search keyword and submit
self.search_field.send_keys('phones')
self.search_field.submit()
# get all the anchor elements which have product names displayed
# currently on result page using find_elements_by_xpath method
products = self.driver\
.find_elements_by_xpath("//h2[@class='product-name']/a")
# check count of products shown in results
self.assertEqual(3, len(products))
def tearDown(self):
# close the browser window
self.driver.quit()
if __name__ == '__main__':
unittest.main(verbosity=2)
针对具体案例,显式案例通常隐式案例要好。
explicit_wait_tests.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
import unittest
class ExplicitWaitTests(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.get('http://demo-store.seleniumacademy.com/')
def test_account_link(self):
WebDriverWait(self.driver, 10)\
.until(lambda s: s.find_element_by_id('select-language').get_attribute('length') == '3')
account = WebDriverWait(self.driver, 10)\
.until(expected_conditions.visibility_of_element_located((By.LINK_TEXT, 'ACCOUNT')))
account.click()
def test_create_new_customer(self):
# click on Log In link to open Login page
self.driver.find_element_by_link_text('ACCOUNT').click()
# wait for My Account link in Menu
my_account = WebDriverWait(self.driver, 10)\
.until(expected_conditions.visibility_of_element_located((By.LINK_TEXT, 'My Account')))
my_account.click()
# get the Create Account button
create_account_button = WebDriverWait(self.driver, 10)\
.until(expected_conditions.element_to_be_clickable((By.LINK_TEXT, 'CREATE AN ACCOUNT')))
# click on Create Account button. This will displayed new account
create_account_button.click()
WebDriverWait(self.driver, 10)\
.until(expected_conditions.title_contains('Create New Customer Account'))
def tearDown(self):
self.driver.quit()
if __name__ == '__main__':
unittest.main(verbosity=2)
expected_conditions类
完整的属性和方法参见:selenium.webdriver.support.expected_conditions
该类的常见方法如下:
Method | Description | Argument | Example |
element_to_be_clickable(locator) | This will wait for an element to be located and be visible and enabled so that it can be clicked. This method returns the element that is located back to the test. | locator: This is a tuple of (by, locator). | WebDriverWait?(self.driver, 10).until(expected_conditions.element_to_be_clickable((By.NAME,“is_subscribed”))) |
element_to_be_selected(element) | This will wait until a specified element is selected. | element: This is the WebElement?. | subscription = self.driver.find_element_by_name(“is_subscribed”) WebDriverWait?(self.driver, 10).until(expected_conditions.element_to_be_selected(subscription)) |
invisibility_of_element_located(locator) | This will wait for an element that is either invisible or is not present on the DOM. | locator: This is a tuple of (by, locator). | WebDriverWait?(self.driver, 10).until(expected_conditions.invisibility_of_element_located((By.ID,“loading_banner”))) |
presence_of_all_elements_located(locator) | This will wait until at least one element for the matching locator is present on the web page. This method returns the list ofWebElements? once they are located. | locator: This is a tuple of (by, locator). | WebDriverWait?(self.driver,10).until(expected_conditions.presence_of_all_elements_located((By.CLASS_NAME,“input-text”))) |
presence_of_element_located(locator) | This will wait until an element for the matching locator is present on a web page or available on the DOM. This method returns an element once it is located. | locator: This is a tuple of (by, locator). | WebDriverWait?(self.driver, 10).until(expected_conditions.presence_of_element_located((By.ID,“search”))) |
text_to_be_present_in_element(locator, text_) | This will wait until an element is located and has the given text. | locator: This is a tuple of (by, locator). text: This is the text to be checked. | WebDriverWait?(self.driver,10).until(expected_conditions.text_to_be_present_in_element((By.ID,“sele language”),“English”)) |
title_contains(title) | This will wait for the page tile to contain a casesensitive substring.This method returns true if the tile matches, false otherwise。 | title: This is the substring of the title to check. | WebDriverWait?(self.driver, 10).until(expected_conditions.title_contains(“Create New Customer Account”)) |
title_is(title) | This will wait for the page tile to be equal to the expected title. This method returns true if the tile matches, false otherwise. | title: This is the title of the page. | WebDriverWait?(self.driver, 10).until(expected_conditions.title_is(“Create New Customer Account -Magento Commerce Demo Store”)) |
visibility_of(element) | This will wait until an element is present in DOM, is visible, and its width and height are greater than zero. This method returns the (same)WebElement? once it becomes visible. | element: This is the WebElement?. | first_name = self.driver.find_element_by_id(“firstname”) WebDriverWait?(self.driver,10).until(expected_conditions.visibility_of(first_name)) |
visibility_of_element_located(locator) | This will wait until an element to be located is present in DOM, is visible, and its width and height are greater than zero. This method returns theWebElement? once it becomes visible. | locator: This is a tuple of (by, locator). | WebDriverWait?(self.driver,10).until(expected_conditions.visibility_of_element_located((By.ID,“firstname”))) |
前一章的弹出窗口处理得不够好,现在我们修改下:comparetests.py
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
import unittest
class CompareProducts(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.get('http://demo-store.seleniumacademy.com/')
def test_compare_products_removal_alert(self):
# get the search textbox
search_field = self.driver.find_element_by_name('q')
search_field.clear()
# enter search keyword and submit
search_field.send_keys('phones')
search_field.submit()
# click the Add to compare link
self.driver.\
find_element_by_link_text('Add to Compare').click()
# wait for Clear All link to be visible
clear_all_link = WebDriverWait(self.driver, 10)\
.until(expected_conditions.visibility_of_element_located((By.LINK_TEXT, 'Clear All')))
# click on Clear All link,
# this will display an alert to the user
clear_all_link.click()
# wait for the alert to present
alert = WebDriverWait(self.driver, 10)\
.until(expected_conditions.alert_is_present())
# get the text from alert
alert_text = alert.text
# check alert text
self.assertEqual('Are you sure you would like to remove all products from your comparison?',
alert_text)
# click on Ok button
alert.accept()
def tearDown(self):
self.driver.quit()
if __name__ == '__main__':
unittest.main(verbosity=2)
参考资料
-
作者:Unmesh Gundecha
-
评审:Adil Imroz:alam.adil12#gmail.com Twitter at @adilimroz
-
评审: Walt Stoneburner: wls#wwco.com Walt.Stoneburner#gmail.com 博客