WebDriver: Advanced Usage
Explicit and Implicit Waits
Waiting is having the automated task execution elapse a certain amount of time before continuing with the next step.Explicit Waits
An explicit waits is code you define to wait for a certain condition to occur before proceeding further in the code. The worst case of this is Thread.sleep(), which sets the condition to an exact time period to wait. There are some convenience methods provided that help you write code that will wait only as long as required. WebDriverWait in combination with ExpectedCondition is one way this can be accomplished.WebDriver driver = new FirefoxDriver();
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(new ExpectedCondition<WebElement>(){
@Override
public WebElement apply(WebDriver d) {
return d.findElement(By.id("myDynamicElement"));
}});
IWebDriver driver = new FirefoxDriver();
driver.Url = "http://somedomain/url_that_delays_loading";
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>
{
return d.FindElement(By.Id("someDynamicElement"));
});
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
ff = webdriver.Firefox()
ff.get("http://somedomain/url_that_delays_loading")
try:
element = WebDriverWait(ff, 10).until(lambda driver : driver.find_element_by_id("myDynamicElement"))
finally:
ff.quit()
require 'rubygems' # not required for ruby 1.9 or if you installed without gem
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
driver.get "http://somedomain/url_that_delays_loading"
wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
begin
element = wait.until { driver.find_element(:id => "some-dynamic-element") }
ensure
driver.quit
end
This example is also functionally equivalent to the first Implicit Waits example.
Expected Conditions
There are some common conditions that are frequently come across when automating web browsers. Listed below are Implementations of each. Java happens to have convienence methods so you don’t have to code an ExpectedCondition class yourself or create your own utility package for them.- Element is Clickable - it is Displayed and Enabled.
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
wait = WebDriverWait(driver, 10)
def clickable(element):
if element.is_clickable():
return element
return null
element = wait.until(lambda d: clickable(d.find_element_by_id('someid')))
Implicit Waits
An implicit wait is to tell WebDriver to poll the DOM for a certain amount of time when trying to find an element or elements if they are not immediately available. The default setting is 0. Once set, the implicit wait is set for the life of the WebDriver object instance.WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = driver.findElement(By.id("myDynamicElement"));
WebDriver driver = new FirefoxDriver();
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
driver.Url = "http://somedomain/url_that_delays_loading";
IWebElement myDynamicElement = driver.FindElement(By.Id("someDynamicElement"));
from selenium import webdriver
ff = webdriver.Firefox()
ff.implicitly_wait(10) # seconds
ff.get("http://somedomain/url_that_delays_loading")
myDynamicElement = ff.find_element_by_id("myDynamicElement")
require 'rubygems' # not required for ruby 1.9 or if you installed without gem
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
driver.manage.timeouts.implicit_wait = 10 # seconds
driver.get "http://somedomain/url_that_delays_loading"
element = driver.find_element(:id => "some-dynamic-element")
RemoteWebDriver
Taking a Screenshot
import java.io.File;
import java.net.URL;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.Augmenter;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
public class Testing {
public void myTest() throws Exception {
WebDriver driver = new RemoteWebDriver(
new URL("http://localhost:4444/wd/hub"),
DesiredCapabilities.firefox());
driver.get("http://www.google.com");
// RemoteWebDriver does not implement the TakesScreenshot class
// if the driver does have the Capabilities to take a screenshot
// then Augmenter will add the TakesScreenshot methods to the instance
WebDriver augmentedDriver = new Augmenter().augment(driver);
File screenshot = ((TakesScreenshot)augmentedDriver).
getScreenshotAs(OutputType.FILE);
}
}
// Add this class to your code and use this instead of RemoteWebDriver
// You will then be able to cast it to ITakesScreenshot and call GetScreenshot
public class ScreenShotRemoteWebDriver : RemoteWebDriver, ITakesScreenshot
{
public ScreenShotRemoteWebDriver(Uri RemoteAdress, ICapabilities capabilities)
: base(RemoteAdress, capabilities)
{
}
/// <summary>
/// Gets a <see cref="Screenshot"/> object representing the image of the page on the screen.
/// </summary>
/// <returns>A <see cref="Screenshot"/> object containing the image.</returns>
public Screenshot GetScreenshot()
{
// Get the screenshot as base64.
Response screenshotResponse = this.Execute(DriverCommand.Screenshot, null);
string base64 = screenshotResponse.Value.ToString();
// ... and convert it.
return new Screenshot(base64);
}
}
// And then the usage would be:
ScreenShotRemoteWebDriver webDriver = new ScreenShotRemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), DesiredCapabilities.Firefox());
// ... do stuff with webDriver
Screenshot ss = ((ITakesScreenshot)webDriver).GetScreenshot();
string screenshot = ss.AsBase64EncodedString;
byte[] screenshotAsByteArray = ss.AsByteArray;
ss.SaveAsFile(activeDir + TestSuiteName + "//" + FileNanme + imageFormat, ImageFormat.Jpeg);
from selenium import webdriver
driver = webdriver.Remote("http://localhost:4444/wd/hub", webdriver.DesiredCapabilities.FIREFOX)
driver.get("http://www.google.com")
driver.get_screenshot_as_file('/Screenshots/google.png')
require 'rubygems'
require 'selenium-webdriver'
begin
driver = Selenium::WebDriver.for :remote, :url => "http://localhost:4444/wd/hub", :desired_capabilities => :firefox
driver.get "http://www.google.com"
driver.save_screenshot "/Screenshots/google.png"
ensure
driver.quit
end
Using a FirefoxProfile
FirefoxProfile fp = new FirefoxProfile();
// set something on the profile...
DesiredCapabilities dc = DesiredCapabilities.firefox();
dc.setCapability(FirefoxDriver.PROFILE, fp);
WebDriver driver = new RemoteWebDriver(dc);
from selenium import webdriver
fp = webdriver.FirefoxProfile()
# set something on the profile...
driver = webdriver.Remote(desired_capabilities=webdriver.DesiredCapabilities.FIREFOX, browser_profile=fp)
Using ChromeOptions
ChromeOptions options = new ChromeOptions();
// set some options
DesiredCapabilities dc = DesiredCapabilities.chrome();
dc.setCapability(ChromeOptions.CAPABILITY, options);
WebDriver driver = new RemoteWebDriver(dc);
from selenium import webdriver
options = webdriver.ChromeOptions()
# set some options
driver = webdriver.Remote(desired_capabilities=options.to_capabilities())
AdvancedUserInteractions
The Actions class(es) allow you to build a Chain of Actions and perform them. There are too many possible combinations to count. Below are a few of the common interactions that you may want to use. For a full list of actions please refer to the API docs Java C# Ruby PythonThe Advanced User Interactions require native events to be enabled. Here’s a table of the current support Matrix for native events:
platform | IE6 | IE7 | IE8 | IE9 | FF3.6 | FF10+ | Chrome stable | Chrome beta | Chrome dev | Opera | Android | iOS |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Windows XP | Y | Y | Y | n/a | Y | Y | Y | Y | Y | ? | Y [1] | n/a |
Windows 7 | n/a | n/a | Y | Y | Y | Y | Y | Y | Y | ? | Y [1] | n/a |
Linux (Ubuntu) | n/a | n/a | n/a | n/a | Y [2] | Y [2] | Y | Y | Y | ? | Y [1] | n/a |
Mac OSX | n/a | n/a | n/a | n/a | N | N | Y | Y | Y | ? | Y [1] | N |
Mobile Device | n/a | n/a | n/a | n/a | n/a | ? | n/a | n/a | n/a | ? | Y | N |
[1] | (1, 2, 3, 4) Using the emulator |
[2] | (1, 2) With explicitly enabling native events |
Browser Startup Manipulation
TodoTopics to be included:
- restoring cookies
- changing firefox profile
- running browsers with plugins
Using a Proxy
Internet Explorer
The easiest and recommended way is to manually set the proxy on the machine that will be running the test. If that is not possible or you want your test to run with a different configuration or proxy, then you can use the following technique that uses a Capababilities object. This temporarily changes the system’s proxy settings and changes them back to the original state when done.String PROXY = "localhost:8080";
org.openqa.selenium.Proxy proxy = new org.openqa.selenium.Proxy();
proxy.setHttpProxy(PROXY)
.setFtpProxy(PROXY)
.setSslProxy(PROXY);
DesiredCapabilities cap = new DesiredCapabailities();
cap.setPreference(CapabilityType.PROXY, proxy);
WebDriver driver = new InternetExplorerDriver(cap);
from selenium import webdriver
PROXY = "localhost:8080"
webdriver.DesiredCapabilities.INTERNETEXPLORER['proxy'] = {
"httpProxy":PROXY,
"ftpProxy":PROXY,
"sslProxy":PROXY,
"noProxy":None,
"proxyType":"MANUAL",
"class":"org.openqa.selenium.Proxy",
"autodetect":False
}
# you have to use remote, otherwise you'll have to code it yourself in python to
# dynamically changing the system proxy preferences
driver = webdriver.Remote("http://localhost:4444/wd/hub", webdriver.DesiredCapabilities.INTERNETEXPLORER)
require 'rubygems'
require 'selenium-webdriver'
PROXY = "localhost:8080"
proxy = Selenium::WebDriver::Proxy.new(
:http => PROXY,
:ftp => PROXY,
:ssl => PROXY
)
caps = Selenium::WebDriver::Remote::Capabilities.ie(:proxy => proxy)
# you have to use remote, otherwise you'll have to code it yourself in ruby to
# dynamically changing the system proxy preferences
driver = Selenium::WebDriver.for :remote, :url => "http://localhost:4444/wd/hub", :desired_capabilities => caps
Chrome
Is basically the same as internet explorer. It uses the same configuration on the machine as IE does (on windows). On Mac it uses the System Preference -> Network settings. On Linux it uses (on Ubuntu) System > Preferences > Network Proxy Preferences (Alternatively in “/etc/environment” set http_proxy). As of this writing it is unknown how to set the proxy programmatically.Firefox
Firefox maintains it’s proxy configuration in a profile. You can preset the proxy in a profile and use that Firefox Profile or you can set it on profile that is created on the fly as is shown in the following example.String PROXY = "localhost:8080";
org.openqa.selenium.Proxy proxy = new org.openqa.selenium.Proxy();
proxy.setHttpProxy(PROXY)
.setFtpProxy(PROXY)
.setSslProxy(PROXY);
DesiredCapabilities cap = new DesiredCapabailities();
cap.setPreference(CapabilityType.PROXY, proxy);
WebDriver driver = new FirefoxDriver(cap);
from selenium import webdriver
PROXY_HOST = "host"
PROXY_PORT = 8080
fp = webdriver.FirefoxProfile()
# Direct = 0, Manual = 1, PAC = 2, AUTODETECT = 4, SYSTEM = 5
fp.set_preference("network.proxy.type", 1)
fp.set_preference("network.proxy.http", PROXY_HOST)
fp.set_preference("network.proxy.http_port", PROXY_PORT)
fp.set_preference("network.proxy.ftp", PROXY_HOST)
fp.set_preference("network.proxy.ftp_port", PROXY_PORT)
fp.set_preference("network.proxy.ssl", PROXY_HOST)
fp.set_preference("network.proxy.ssl_port", PROXY_PORT)
fp.set_preference("network.proxy.no_proxies_on", "") # set this value as desired
driver = webdriver.Firefox(firefox_profile=fp)
require 'rubygems'
require 'selenium-webdriver'
PROXY = 'localhost:8087'
profile = Selenium::WebDriver::Firefox::Profile.new
profile.proxy = Selenium::WebDriver::Proxy.new(
:http => PROXY,
:ftp => PROXY,
:ssl => PROXY
)
driver = Selenium::WebDriver.for :firefox, :profile => profile
沒有留言:
張貼留言