Total Pageviews

Monday 28 May 2012

Selenium Documentation 2

3.14. Locating Elements 29
Selenium Documentation, Release 1.0
or name attributes, and opens up all sorts of new possibilities such as locating the third checkbox on the
page.
One of the main reasons for using XPath is when you don’t have a suitable id or name attribute for
the element you wish to locate. You can use XPath to either locate the element in absolute terms (not
advised), or relative to an element that does have an id or name attribute. XPath locators can also be
used to specify elements via attributes other than id and name.
Absolute XPaths contain the location of all elements from the root (html) and as a result are likely to fail
with only the slightest adjustment to the application. By finding a nearby element with an id or name
attribute (ideally a parent element) you can locate your target element based on the relationship. This is
much less likely to change and can make your tests more robust.
Since only xpath locators start with “//”, it is not necessary to include the xpath= label when specifying
an XPath locator.
1 <html>
2 <body>
3 <form id= "loginForm" >
4 <input name= "username" type= "text" />
5 <input name= "password" type= "password" />
6 <input name= "continue" type= "submit" value= "Login" />
7 <input name= "continue" type= "button" value= "Clear" />
8 </form>
9 </body>
10 <html>
xpath=/html/body/form[1] (3) - Absolute path (would break if the HTML was changed
only slightly)
//form[1] (3) - First form element in the HTML
xpath=//form[@id=’loginForm’] (3) - The form element with attribute named ‘id’ and
the value ‘loginForm’
xpath=//form[input/\@name=’username’] (3) - First form element with an input
child element with attribute named ‘name’ and the value ‘username’
//input[@name=’username’] (4) - First input element with attribute named ‘name’ and
the value ‘username’
//form[@id=’loginForm’]/input[1] (4) - First input child element of the form element
with attribute named ‘id’ and the value ‘loginForm’
//input[@name=’continue’][@type=’button’] (7) - Input with attribute named
‘name’ and the value ‘continue’ and attribute named ‘type’ and the value ‘button’
//form[@id=’loginForm’]/input[4] (7) - Fourth input child element of the form element
with attribute named ‘id’ and value ‘loginForm’
These examples cover some basics, but in order to learn more, the following references are recommended:
W3Schools XPath Tutorial
W3C XPath Recommendation
30 Chapter 3. Selenium-IDE
Selenium Documentation, Release 1.0
There are also a couple of very useful Firefox Add-ons that can assist in discovering the XPath of an
element:
XPath Checker - suggests XPath and can be used to test XPath results.
Firebug - XPath suggestions are just one of the many powerful features of this very useful add-on.
Locating Hyperlinks by Link Text
This is a simple method of locating a hyperlink in your web page by using the text of the link. If two
links with the same text are present, then the first match will be used.
1 <html>
2 <body>
3 <p>Are you sure you want to do this?</p>
4 <a href= "continue.html" >Continue</a>
5 <a href= "cancel.html" >Cancel</a>
6 </body>
7 <html>
link=Continue (4)
link=Cancel (5)
Locating by DOM
The Document Object Model represents an HTML document and can be accessed using JavaScript.
This location strategy takes JavaScript that evaluates to an element on the page, which can be simply the
element’s location using the hierarchical dotted notation.
Since only dom locators start with “document”, it is not necessary to include the dom= label when
specifying a DOM locator.
1 <html>
2 <body>
3 <form id= "loginForm" >
4 <input name= "username" type= "text" />
5 <input name= "password" type= "password" />
6 <input name= "continue" type= "submit" value= "Login" />
7 <input name= "continue" type= "button" value= "Clear" />
8 </form>
9 </body>
10 <html>
dom=document.getElementById(’loginForm’) (3)
dom=document.forms[’loginForm’] (3)
dom=document.forms[0] (3)
document.forms[0].username (4)
document.forms[0].elements[’username’] (4)
3.14. Locating Elements 31
Selenium Documentation, Release 1.0
document.forms[0].elements[0] (4)
document.forms[0].elements[3] (7)
You can use Selenium itself as well as other sites and extensions to explore the DOM of your web
application. A good reference exists on W3Schools.
Locating by CSS
CSS (Cascading Style Sheets) is a language for describing the rendering of HTML and XML documents.
CSS uses Selectors for binding style properties to elements in the document. These Selectors can be used
by Selenium as another locating strategy.
1 <html>
2 <body>
3 <form id= "loginForm" >
4 <input class= "required" name= "username" type= "text" />
5 <input class= "required passfield" name= "password" type= "password" />
6 <input name= "continue" type= "submit" value= "Login" />
7 <input name= "continue" type= "button" value= "Clear" />
8 </form>
9 </body>
10 <html>
css=form#loginForm (3)
css=input[name="username"] (4)
css=input.required[type="text"] (4)
css=input.passfield (5)
css=#loginForm input[type="button"] (4)
css=#loginForm input:nth-child(2) (5)
For more information about CSS Selectors, the best place to go is the W3C publication. You’ll find
additional references there.
Note: Most experienced Selenium users recommend CSS as their locating strategy of choice as it’s
considerably faster than XPath and can find the most complicated objects in an intrinsic HTML document.
Implicit Locators
You can choose to omit the locator type in the following situations:
• Locators without an explicitly defined locator strategy will default to using the identifier locator
strategy. See Locating by Identifier.
• Locators starting with “//” will use the XPath locator strategy. See Locating by XPath.
• Locators starting with “document” will use the DOM locator strategy. See Locating by DOM
32 Chapter 3. Selenium-IDE
Selenium Documentation, Release 1.0
3.15 Matching Text Patterns
Like locators, patterns are a type of parameter frequently required by Selenese commands. Examples
of commands which require patterns are verifyTextPresent, verifyTitle, verifyAlert, assertConfirmation,
verifyText, and verifyPrompt. And as has been mentioned above, link locators can utilize a
pattern. Patterns allow you to describe, via the use of special characters, what text is expected rather
than having to specify that text exactly.
There are three types of patterns: globbing, regular expressions, and exact.
3.15.1 Globbing Patterns
Most people are familiar with globbing as it is utilized in filename expansion at a DOS or Unix/Linux
command line such as ls *.c. In this case, globbing is used to display all the files ending with a .c
extension that exist in the current directory. Globbing is fairly limited. Only two special characters are
supported in the Selenium implementation:
* which translates to “match anything,” i.e., nothing, a single character, or many characters.
[ ] (character class) which translates to “match any single character found inside the square
brackets.” A dash (hyphen) can be used as a shorthand to specify a range of characters
(which are contiguous in the ASCII character set). A few examples will make the functionality
of a character class clear:
[aeiou] matches any lowercase vowel
[0-9] matches any digit
[a-zA-Z0-9] matches any alphanumeric character
In most other contexts, globbing includes a third special character, the ?. However, Selenium globbing
patterns only support the asterisk and character class.
To specify a globbing pattern parameter for a Selenese command, you can prefix the pattern with a glob:
label. However, because globbing patterns are the default, you can also omit the label and specify just
the pattern itself.
Below is an example of two commands that use globbing patterns. The actual link text on the page
being tested was “Film/Television Department”; by using a pattern rather than the exact text, the click
command will work even if the link text is changed to “Film & Television Department” or “Film and
Television Department”. The glob pattern’s asterisk will match “anything or nothing” between the word
“Film” and the word “Television”.
Command Target Value
click link=glob:Film*Television Department
verifyTitle glob:*Film*Television*
The actual title of the page reached by clicking on the link was “De Anza Film And Television Department
- Menu”. By using a pattern rather than the exact text, the verifyTitle will pass as long as
the two words “Film” and “Television” appear (in that order) anywhere in the page’s title. For example,
if the page’s owner should shorten the title to just “Film & Television Department,” the test would still
pass. Using a pattern for both a link and a simple test that the link worked (such as the verifyTitle
above does) can greatly reduce the maintenance for such test cases.
3.15. Matching Text Patterns 33
Selenium Documentation, Release 1.0
Regular Expression Patterns
Regular expression patterns are the most powerful of the three types of patterns that Selenese supports.
Regular expressions are also supported by most high-level programming languages, many text editors,
and a host of tools, including the Linux/Unix command-line utilities grep, sed, and awk. In Selenese,
regular expression patterns allow a user to perform many tasks that would be very difficult otherwise.
For example, suppose your test needed to ensure that a particular table cell contained nothing but a
number. regexp: [0-9]+ is a simple pattern that will match a decimal number of any length.
Whereas Selenese globbing patterns support only the * and [ ] (character class) features, Selenese regular
expression patterns offer the same wide array of special characters that exist in JavaScript. Below are a
subset of those special characters:
PATTERN MATCH
. any single character
[ ] character class: any single character that appears inside the brackets
* quantifier: 0 or more of the preceding character (or group)
+ quantifier: 1 or more of the preceding character (or group)
? quantifier: 0 or 1 of the preceding character (or group)
{1,5} quantifier: 1 through 5 of the preceding character (or group)
| alternation: the character/group on the left or the character/group on the right
( ) grouping: often used with alternation and/or quantifier
Regular expression patterns in Selenese need to be prefixed with either regexp: or regexpi:. The
former is case-sensitive; the latter is case-insensitive.
A few examples will help clarify how regular expression patterns can be used with Selenese commands.
The first one uses what is probably the most commonly used regular expression pattern–.* (“dot star”).
This two-character sequence can be translated as “0 or more occurrences of any character” or more
simply, “anything or nothing.” It is the equivalent of the one-character globbing pattern * (a single
asterisk).
Command Target Value
click link=regexp:Film.*Television Department
verifyTitle regexp:.*Film.*Television.*
The example above is functionally equivalent to the earlier example that used globbing patterns for this
same test. The only differences are the prefix (regexp: instead of glob:) and the “anything or nothing”
pattern (.* instead of just *).
The more complex example below tests that the Yahoo! Weather page for Anchorage, Alaska contains
info on the sunrise time:
Command Target Value
open http://weather.yahoo.com/forecast/USAK0012.html
verifyTextPresent regexp:Sunrise: *[0-9]{1,2}:[0-9]{2} [ap]m
Let’s examine the regular expression above one part at a time:
Sunrise: * The string Sunrise: followed by 0 or more spaces
[0-9]{1,2} 1 or 2 digits (for the hour of the day)
: The character : (no special characters involved)
[0-9]{2} 2 digits (for the minutes) followed by a space
[ap]m “a” or “p” followed by “m” (am or pm)
34 Chapter 3. Selenium-IDE
Selenium Documentation, Release 1.0
Exact Patterns
The exact type of Selenium pattern is of marginal usefulness. It uses no special characters at all. So,
if you needed to look for an actual asterisk character (which is special for both globbing and regular
expression patterns), the exact pattern would be one way to do that. For example, if you wanted to
select an item labeled “Real *” from a dropdown, the following code might work or it might not. The
asterisk in the glob:Real * pattern will match anything or nothing. So, if there was an earlier select
option labeled “Real Numbers,” it would be the option selected rather than the “Real *” option.
select //select glob:Real *
In order to ensure that the “Real *” item would be selected, the exact: prefix could be used to create
an exact pattern as shown below:
select //select exact:Real *
But the same effect could be achieved via escaping the asterisk in a regular expression pattern:
select //select regexp:Real \*
It’s rather unlikely that most testers will ever need to look for an asterisk or a set of square brackets with
characters inside them (the character class for globbing patterns). Thus, globbing patterns and regular
expression patterns are sufficient for the vast majority of us.
3.16 The “AndWait” Commands
The difference between a command and its AndWait alternative is that the regular command (e.g. click)
will do the action and continue with the following command as fast as it can, while the AndWait alternative
(e.g. clickAndWait) tells Selenium to wait for the page to load after the action has been done.
The AndWait alternative is always used when the action causes the browser to navigate to another page
or reload the present one.
Be aware, if you use an AndWait command for an action that does not trigger a navigation/refresh,
your test will fail. This happens because Selenium will reach the AndWait‘s timeout without seeing any
navigation or refresh being made, causing Selenium to raise a timeout exception.
3.17 The waitFor Commands in AJAX applications
In AJAX driven web applications, data is retrieved from server without refreshing the page. Using
andWait commands will not work as the page is not actually refreshed. Pausing the test execution for
a certain period of time is also not a good approach as web element might appear later or earlier than
the stipulated period depending on the system’s responsiveness, load or other uncontrolled factors of
the moment, leading to test failures. The best approach would be to wait for the needed element in a
dynamic period and then continue the execution as soon as the element is found.
This is done using waitFor commands, as waitForElementPresent or waitForVisible, which wait dynamically,
checking for the desired condition every second and continuing to the next command in the script
as soon as the condition is met.
3.18 Sequence of Evaluation and Flow Control
When a script runs, it simply runs in sequence, one command after another.
3.16. The “AndWait” Commands 35
Selenium Documentation, Release 1.0
Selenese, by itself, does not support condition statements (if-else, etc.) or iteration (for, while, etc.).
Many useful tests can be conducted without flow control. However, for a functional test of dynamic
content, possibly involving multiple pages, programming logic is often needed.
When flow control is needed, there are three options:
1. Run the script using Selenium-RC and a client library such as Java or PHP to utilize the programming
language’s flow control features.
2. Run a small JavaScript snippet from within the script using the storeEval command.
3. Install the goto_sel_ide.js extension.
Most testers will export the test script into a programming language file that uses the Selenium-RC API
(see the Selenium-IDE chapter). However, some organizations prefer to run their scripts from Selenium-
IDE whenever possible (for instance, when they have many junior-level people running tests for them,
or when programming skills are lacking). If this is your case, consider a JavaScript snippet or the
goto_sel_ide.js extension.
3.19 Store Commands and Selenium Variables
You can use Selenium variables to store constants at the beginning of a script. Also, when combined
with a data-driven test design (discussed in a later section), Selenium variables can be used to store
values passed to your test program from the command-line, from another program, or from a file.
The plain store command is the most basic of the many store commands and can be used to simply
store a constant value in a selenium variable. It takes two parameters, the text value to be stored and a
selenium variable. Use the standard variable naming conventions of only alphanumeric characters when
choosing a name for your variable.
Command Target Value
store paul@mysite.org userName
Later in your script, you’ll want to use the stored value of your variable. To access the value of a variable,
enclose the variable in curly brackets ({}) and precede it with a dollar sign like this.
Command Target Value
verifyText //div/p ${userName}
A common use of variables is for storing input for an input field.
Command Target Value
type id=login ${userName}
Selenium variables can be used in either the first or second parameter and are interpreted by Selenium
prior to any other operations performed by the command. A Selenium variable may also be used within
a locator expression.
An equivalent store command exists for each verify and assert command. Here are a couple more
commonly used store commands.
3.19.1 storeElementPresent
This corresponds to verifyElementPresent. It simply stores a boolean value–“true” or “false”–depending
on whether the UI element is found.
36 Chapter 3. Selenium-IDE
Selenium Documentation, Release 1.0
3.19.2 storeText
StoreText corresponds to verifyText. It uses a locater to identify specific page text. The text, if found, is
stored in the variable. StoreText can be used to extract text from the page being tested.
3.19.3 storeEval
This command takes a script as its first parameter. Embedding JavaScript within Selenese is covered in
the next section. StoreEval allows the test to store the result of running the script in a variable.
3.20 JavaScript and Selenese Parameters
JavaScript can be used with two types of Selenese parameters: script and non-script (usually expressions).
In most cases, you’ll want to access and/or manipulate a test case variable inside the
JavaScript snippet used as a Selenese parameter. All variables created in your test case are stored in
a JavaScript associative array. An associative array has string indexes rather than sequential numeric
indexes. The associative array containing your test case’s variables is named storedVars. Whenever
you wish to access or manipulate a variable within a JavaScript snippet, you must refer to it as stored-
Vars[’yourVariableName’].
3.20.1 JavaScript Usage with Script Parameters
Several Selenese commands specify a script parameter including assertEval, verifyEval, storeEval,
and waitForEval. These parameters require no special syntax. A Selenium-IDE user would simply
place a snippet of JavaScript code into the appropriate field, normally the Target field (because a script
parameter is normally the first or only parameter).
The example below illustrates how a JavaScript snippet can be used to perform a simple numerical
calculation:
Command Target Value
store 10 hits
storeXpathCount //blockquote blockquotes
storeEval storedVars[’hits’]-storedVars[’blockquotes’] paragraphs
This next example illustrates how a JavaScript snippet can include calls to methods, in this case the
JavaScript String object’s toUpperCase method and toLowerCase method.
Command Target Value
store Edith Wharton name
storeEval storedVars[’name’].toUpperCase() uc
storeEval storedVars[’name’].toLowerCase() lc
JavaScript Usage with Non-Script Parameters
JavaScript can also be used to help generate values for parameters, even when the parameter is not
specified to be of type script. However, in this case, special syntax is required–the JavaScript snippet
must be enclosed inside curly braces and preceded by the label javascript, as in javascript
{*yourCodeHere*}. Below is an example in which the type command’s second parameter value
is generated via JavaScript code using this special syntax:
3.20. JavaScript and Selenese Parameters 37
Selenium Documentation, Release 1.0
Command Target Value
store league of nations searchString
type q javascript{storedVars[’searchString’].toUpperCase()}
3.21 echo - The Selenese Print Command
Selenese has a simple command that allows you to print text to your test’s output. This is useful for
providing informational progress notes in your test which display on the console as your test is running.
These notes also can be used to provide context within your test result reports, which can be useful for
finding where a defect exists on a page in the event your test finds a problem. Finally, echo statements
can be used to print the contents of Selenium variables.
Command Target Value
echo Testing page footer now.
echo Username is ${userName}
3.22 Alerts, Popups, and Multiple Windows
Suppose that you are testing a page that looks like this.
1 <!DOCTYPE HTML>
2 <html>
3 <head>
4 <script type= "text/javascript" >
5 function output(resultText){
6 document.getElementById( ’output’ ).childNodes[0].nodeValue=resultText;
7 }
8
9 function show_confirm(){
10 var confirmation=confirm( "Chose an option." );
11 if (confirmation==true){
12 output( "Confirmed." );
13 }
14 else{
15 output( "Rejected!" );
16 }
17 }
18
19 function show_alert(){
20 alert( "I’m blocking!" );
21 output( "Alert is gone." );
22 }
23 function show_prompt(){
24 var response = prompt( "What’s the best web QA tool?" , "Selenium" );
25 output(response);
26 }
27 function open_window(windowName){
28 window.open( "newWindow.html" ,windowName);
29 }
30 </script>
31 </head>
32 <body>
33
38 Chapter 3. Selenium-IDE
Selenium Documentation, Release 1.0
34 <input type= "button" id= "btnConfirm" onclick= "show_confirm()" value= "Show confirm box" 35 <input type= "button" id= "btnAlert" onclick= "show_alert()" value= "Show alert" />
36 <input type= "button" id= "btnPrompt" onclick= "show_prompt()" value= "Show prompt" />
37 <a href= "newWindow.html" id= "lnkNewWindow" target= "_blank" >New Window Link</a>
38 <input type= "button" id= "btnNewNamelessWindow" onclick= "open_window()" value= "Open 39 <input type= "button" id= "btnNewNamedWindow" onclick= "open_window(’Mike’)" value= "Open 40
41 <br />
42 <span id= "output" >
43 </span>
44 </body>
45 </html>
The user must respond to alert/confirm boxes, as well as moving focus to newly opened popup windows.
Fortunately, Selenium can cover JavaScript pop-ups.
But before we begin covering alerts/confirms/prompts in individual detail, it is helpful to understand the
commonality between them. Alerts, confirmation boxes and prompts all have variations of the following
Command Description
assertFoo(pattern) throws error if pattern doesn’t match the text of the pop-up
assertFooPresent throws error if pop-up is not available
assertFooNotPresent throws error if any pop-up is present
storeFoo(variable) stores the text of the pop-up in a variable
storeFooPresent(variable) stores the text of the pop-up in a variable and returns true or false
When running under Selenium, JavaScript pop-ups will not appear. This is because the function calls
are actually being overridden at runtime by Selenium’s own JavaScript. However, just because you
cannot see the pop-up doesn’t mean you don’t have to deal with it. To handle a pop-up, you must call its
assertFoo(pattern) function. If you fail to assert the presence of a pop-up your next command
will be blocked and you will get an error similar to the following [error] Error: There was
an unexpected Confirmation! [Chose an option.]
3.22.1 Alerts
Let’s start with alerts because they are the simplest pop-up to handle. To begin, open the HTML sample
above in a browser and click on the “Show alert” button. You’ll notice that after you close the alert
the text “Alert is gone.” is displayed on the page. Now run through the same steps with Selenium IDE
recording, and verify the text is added after you close the alert. Your test will look something like this:
Command Target Value
open /
click btnAlert
assertAlert I’m blocking!
verifyTextPresent Alert is gone.
You may be thinking “That’s odd, I never tried to assert that alert.” But this is Selenium-IDE handling
and closing the alert for you. If you remove that step and replay the test you will get the following error
[error] Error: There was an unexpected Alert! [I’m blocking!]. You
must include an assertion of the alert to acknowledge its presence.
If you just want to assert that an alert is present but either don’t know or don’t care what text it contains,
you can use assertAlertPresent. This will return true or false, with false halting the test.
3.22. Alerts, Popups, and Multiple Windows 39
Selenium Documentation, Release 1.0
Confirmations
Confirmations behave in much the same way as alerts, with assertConfirmation and
assertConfirmationPresent offering the same characteristics as their alert counterparts. However,
by default Selenium will select OK when a confirmation pops up. Try recording clicking on the
“Show confirm box” button in the sample page, but click on the “Cancel” button in the popup, then
assert the output text. Your test may look something like this:
Command Target Value
open /
click btnConfirm
chooseCancelOnNextConfirmation
assertConfirmation Choose an option.
verifyTextPresent Rejected
The chooseCancelOnNextConfirmation function tells Selenium that all following confirmation
should return false. It can be reset by calling chooseOkOnNextConfirmation.
You may notice that you cannot replay this test, because Selenium complains that there is an unhandled
confirmation. This is because the order of events Selenium-IDE records causes the click and choose-
CancelOnNextConfirmation to be put in the wrong order (it makes sense if you think about it, Selenium
can’t know that you’re cancelling before you open a confirmation) Simply switch these two commands
and your test will run fine.
3.23 Debugging
Debugging means finding and fixing errors in your test case. This is a normal part of test case development.
We won’t teach debugging here as most new users to Selenium will already have some basic experience
with debugging. If this is new to you, we recommend you ask one of the developers in your organization.
3.23.1 Breakpoints and Startpoints
The Sel-IDE supports the setting of breakpoints and the ability to start and stop the running of a test
case, from any point within the test case. That is, one can run up to a specific command in the middle
of the test case and inspect how the test case behaves at that point. To do this, set a breakpoint on the
command just before the one to be examined.
To set a breakpoint, select a command, right-click, and from the context menu select Toggle Breakpoint.
Then click the Run button to run your test case from the beginning up to the breakpoint.
It is also sometimes useful to run a test case from somewhere in the middle to the end of the test case or
up to a breakpoint that follows the starting point. For example, suppose your test case first logs into the
website and then performs a series of tests and you are trying to debug one of those tests. However, you
only need to login once, but you need to keep rerunning your tests as you are developing them. You can
login once, then run your test case from a startpoint placed after the login portion of your test case. That
will prevent you from having to manually logout each time you rerun your test case.
To set a startpoint, select a command, right-click, and from the context menu select Set/Clear Start Point.
Then click the Run button to execute the test case beginning at that startpoint.
40 Chapter 3. Selenium-IDE
Selenium Documentation, Release 1.0
3.23.2 Stepping Through a Testcase
To execute a test case one command at a time (“step through” it), follow these steps:
1. Start the test case running with the Run button from the toolbar.
1. Immediately pause the executing test case with the Pause button.
1. Repeatedly select the Step button.
3.23.3 Find Button
The Find button is used to see which UI element on the currently displayed webpage (in the browser)
is used in the currently selected Selenium command. This is useful when building a locator for a command’s
first parameter (see the section on locators in the Selenium Commands chapter). It can be used
with any command that identifies a UI element on a webpage, i.e. click, clickAndWait, type, and certain
assert and verify commands, among others.
From Table view, select any command that has a locator parameter. Click the Find button. Now look
on the webpage: There should be a bright green rectangle enclosing the element specified by the locator
parameter.
3.23.4 Page Source for Debugging
Often, when debugging a test case, you simply must look at the page source (the HTML for the webpage
you’re trying to test) to determine a problem. Firefox makes this easy. Simply right-click the
webpage and select ‘View->Page Source. The HTML opens in a separate window. Use its Search
feature (Edit=>Find) to search for a keyword to find the HTML for the UI element you’re trying to test.
Alternatively, select just that portion of the webpage for which you want to see the source. Then rightclick
the webpage and select View Selection Source. In this case, the separate HTML window will
contain just a small amount of source, with highlighting on the portion representing your selection.
3.23.5 Locator Assistance
Whenever Selenium-IDE records a locator-type argument, it stores additional information which allows
the user to view other possible locator-type arguments that could be used instead. This feature can be
very useful for learning more about locators, and is often needed to help one build a different type of
locator than the type that was recorded.
This locator assistance is presented on the Selenium-IDE window as a drop-down list accessible at the
right end of the Target field (only when the Target field contains a recorded locator-type argument).
Below is a snapshot showing the contents of this drop-down for one command. Note that the first
3.23. Debugging 41
Selenium Documentation, Release 1.0
column of the drop-down provides alternative locators, whereas the second column indicates the type of
each alternative.
3.24 Writing a Test Suite
A test suite is a collection of test cases which is displayed in the leftmost pane in the IDE. The test suite
pane can be manually opened or closed via selecting a small dot halfway down the right edge of the pane
(which is the left edge of the entire Selenium-IDE window if the pane is closed).
The test suite pane will be automatically opened when an existing test suite is opened or when the user
selects the New Test Case item from the File menu. In the latter case, the new test case will appear
immediately below the previous test case.
Selenium-IDE also supports loading pre-existing test cases by using the File -> Add Test Case menu
option. This allows you to add existing test cases to a new test suite.
A test suite file is an HTML file containing a one-column table. Each cell of each row in the <tbody>
section contains a link to a test case. The example below is of a test suite containing four test cases:
<html>
<head>
<meta http-equiv= "Content-Type" content= "text/html; charset=UTF-8" >
<title>Sample Selenium Test Suite</title>
</head>
42 Chapter 3. Selenium-IDE
Selenium Documentation, Release 1.0
<body>
<table cellpadding= "1" cellspacing= "1" border= "1" >
<thead>
<tr><td>Test Cases for De Anza A-Z Directory Links</td></tr>
</thead>
<tbody>
<tr><td><a href= "./a.html" >A Links</a></td></tr>
<tr><td><a href= "./b.html" >B Links</a></td></tr>
<tr><td><a href= "./c.html" >C Links</a></td></tr>
<tr><td><a href= "./d.html" >D Links</a></td></tr>
</tbody>
</table>
</body>
</html>
Note: Test case files should not have to be co-located with the test suite file that invokes them. And on
Mac OS and Linux systems, that is indeed the case. However, at the time of this writing, a bug prevents
Windows users from being able to place the test cases elsewhere than with the test suite that invokes
them.
3.25 User Extensions
User extensions are JavaScript files that allow one to create his or her own customizations and features
to add additional functionality. Often this is in the form of customized commands although this
extensibility is not limited to additional commands.
There are a number of useful extensions created by users.
IMPORTANT: THIS SECTION IS OUT OF DATE–WE WILL BE REVISING THIS SOON. Perhaps the
most popular of all Selenium-IDE extensions is one which provides flow control in the form of while
loops and primitive conditionals. This extension is the goto_sel_ide.js. For an example of how to use
the functionality provided by this extension, look at the page created by its author.
To install this extension, put the pathname to its location on your computer in the Selenium Core
extensions field of Selenium-IDE’s Options=>Options=>General tab.
After selecting the OK button, you must close and reopen Selenium-IDE in order for the extensions file
to be read. Any change you make to an extension will also require you to close and reopen Selenium-
IDE.
3.25. User Extensions 43
Selenium Documentation, Release 1.0
Information on writing your own extensions can be found near the bottom of the Selenium Reference
document.
3.26 Format
Format, under the Options menu, allows you to select a language for saving and displaying the test case.
The default is HTML.
If you will be using Selenium-RC to run your test cases, this feature is used to translate your test case
into a programming language. Select the language, e.g. Java, PHP, you will be using with Selenium-
RC for developing your test programs. Then simply save the test case using File=>Export Test Case
As. Your test case will be translated into a series of functions in the language you choose. Essentially,
program code supporting your test is generated for you by Selenium-IDE.
Also, note that if the generated code does not suit your needs, you can alter it by editing a configuration
file which defines the generation process. Each supported language has configuration settings which are
editable. This is under the Options=>Options=>Formats tab.
Note: At the time of this writing, this feature is not yet supported by the Selenium developers. However
the author has altered the C# format in a limited manner and it has worked well.
3.27 Executing Selenium-IDE Tests on Different Browsers
While Selenium-IDE can only run tests against Firefox, tests developed with Selenium-IDE can be run
against other browsers, using a simple command-line interface that invokes the Selenium-RC server.
This topic is covered in the Run Selenese tests section on Selenium-RC chapter. The -htmlSuite
command-line option is the particular feature of interest.
3.28 Troubleshooting
Below is a list of image/explanation pairs which describe frequent sources of problems with Selenium-
IDE:
Table view is not available with this format.
This message can be occasionally displayed in the Table tab when Selenium IDE is launched. The
workaround is to close and reopen Selenium IDE. See issue 1008. for more information. If you are able
to reproduce this reliably then please provide details so that we can work on a fix.
error loading test case: no command found
You’ve used File=>Open to try to open a test suite file. Use File=>Open Test Suite instead.
An enhancement request has been raised to improve this error message. See issue 1010.
44 Chapter 3. Selenium-IDE
Selenium Documentation, Release 1.0
This type of error may indicate a timing problem, i.e., the element specified by a locator in your command
wasn’t fully loaded when the command was executed. Try putting a pause 5000 before the command
to determine whether the problem is indeed related to timing. If so, investigate using an appropriate
waitFor* or *AndWait command before the failing command.
Whenever your attempt to use variable substitution fails as is the case for the open command above,
it indicates that you haven’t actually created the variable whose value you’re trying to access. This is
sometimes due to putting the variable in the Value field when it should be in the Target field or vice
versa. In the example above, the two parameters for the store command have been erroneously placed
in the reverse order of what is required. For any Selenese command, the first required parameter must
go in the Target field, and the second required parameter (if one exists) must go in the Value field.
error loading test case: [Exception... “Component returned failure code: 0x80520012
(NS_ERROR_FILE_NOT_FOUND) [nsIFileInputStream.init]” nresult: “0x80520012
(NS_ERROR_FILE_NOT_FOUND)” location: “JS frame :: chrome://selenium-ide/content/fileutils.
js :: anonymous :: line 48” data: no]
One of the test cases in your test suite cannot be found. Make sure that the test case is indeed located
where the test suite indicates it is located. Also, make sure that your actual test case files have the .html
extension both in their filenames, and in the test suite file where they are referenced.
An enhancement request has been raised to improve this error message. See issue 1011.
Your extension file’s contents have not been read by Selenium-IDE. Be sure you have specified the proper
pathname to the extensions file via Options=>Options=>General in the Selenium Core extensions
3.28. Troubleshooting 45
Selenium Documentation, Release 1.0
field. Also, Selenium-IDE must be restarted after any change to either an extensions file or to the
contents of the Selenium Core extensions field.
46 Chapter 3. Selenium-IDE
CHAPTER
FOUR
SELENIUM WEBDRIVER
NOTE: We’re currently working on documenting these sections. We believe the information here is
accurate, however be aware we are also still working on this chapter. Additional information will be
provided as we go which should make this chapter more solid.
4.1 Introducing WebDriver
The primary new feature in Selenium 2.0 is the integration of theWebDriver API.WebDriver is designed
to providing an simpler, more concise programming interface along with addressing some limitations in
the Selenium-RC API. Selenium-WebDriver was developed to better support dynamic web pages where
elements of a page may change without the page itself being reloaded. WebDriver’s goal is to supply a
well-designed object-oriented API that provides improved support for modern advanced web-app testing
problems.
4.2 How Does WebDriver ‘Drive’ the Browser Compared to
Selenium-RC?
Selenium-WebDriver makes direct calls to the browser using each browser’s native support for automation.
How these direct calls are made, and the features they support depends on the browser you are
using. Information on each ‘browser driver’ is provided later in this chapter.
For those familiar with Selenium-RC, this is quite different from what you are used to. Selenium-RC
worked the same way for each supported browser. It ‘injected’ javascript functions into the browser when
the browser was loaded and then used its javascript to drive the AUT within the browser. WebDriver
does not use this technique. Again, it drives the browser directly using the browser’s built in support for
automation.
4.3 WebDriver and the Selenium-Server
You may, or may not, need the Selenium Server, depending on how you intend to use Selenium-
WebDriver. If you will be only using the WebDriver API you do not need the Selenium-Server. If
your browser and tests will all run on the same machine, and your tests only use the WebDriver API,
then you do not need to run the Selenium-Server; WebDriver will run the browser directly.
There are some reasons though to use the Selenium-Server with Selenium-WebDriver.
• You are using Selenium-Grid to distribute your tests over multiple machines or virtual machines
(VMs).
47
Selenium Documentation, Release 1.0
• You want to connect to a remote machine that has a particular browser version that is not on your
current machine.
• You are not using the Java bindings (i.e. Python, C#, or Ruby) and would like to use HtmlUnit
Driver
4.4 Setting Up a Selenium-WebDriver Project
To install Selenium means to set up a project in a development so you can write a program using Selenium.
How you do this depends on your programming language and your development environment.
4.4.1 Java
The easiest way to set up a Selenium 2.0 Java project is to use Maven. Maven will download the java
bindings (the Selenium 2.0 java client library) and all its dependencies, and will create the project for
you, using a maven pom.xml (project configuration) file. Once you’ve done this, you can import the
maven project into your preferred IDE, IntelliJ IDEA or Eclipse.
First, create a folder to contain your Selenium project files. Then, to use Maven, you need a pom.xml
file. This can be created with a text editor. We won’t teach the details of pom.xml files or for using
Maven since there are already excellent references on this. Your pom.xml file will look something like
this. Create this file in the folder you created for your project.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns= "http://maven.apache.org/POM/4.0.0"
xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation= "http://maven.apache.org/POM/4.0.0 http://maven.apache.<modelVersion>4.0.0</modelVersion>
<groupId>MySel20Proj</groupId>
<artifactId>MySel20Proj</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.21.0</version>
</dependency>
<dependency>
<groupId>com.opera</groupId>
<artifactId>operadriver</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.opera</groupId>
<artifactId>operadriver</artifactId>
<version>0.13</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
48 Chapter 4. Selenium WebDriver
Selenium Documentation, Release 1.0
Be sure you specify the most current version. At the time of writing, the version listed above was the
most current, however there were frequent releases immediately after the release of Selenium 2.0. Check
the Maven download page for the current release and edit the above dependency accordingly.
Now, from a command-line, CD into the project directory and run maven as follows.
mvn clean install
This will download Selenium and all its dependencies and will add them to the project.
Finally, import the project into your preferred development environment. For those not familiar with
this, we’ve provided an appendix which shows this.
Importing a maven project into IntelliJ IDEA. Importing a maven project into Eclipse.
4.4.2 C#
As of Selenium 2.2.0, the C# bindings are distributed as a set of signed dlls along with other dependency
dlls. Prior to 2.2.0, all Selenium dll’s were unsigned. To include Selenium in your project, simply
download the latest selenium-dotnet zip file from https://code.google.com/p/selenium/downloads/list. If
you are using Windows Vista or above, you should unblock the zip file before unzipping it: Right click
on the zip file, click “Properties”, click “Unblock” and click “OK”.
Unzip the contents of the zip file, and add a reference to each of the unzipped dlls to your project in
Visual Studio (or your IDE of choice).
Official NuGet Packages: RC WebDriver WebDriverBackedSelenium Support
4.4.3 Python
If you are using Python for test automation then you probably are already familiar with developing in
Python. To add Selenium to your Python environment run the following command from a commandline.
pip install selenium
Pip requires pip to be installed, pip also has a dependency on setuptools.
Teaching Python development itself is beyond the scope of this document, however there are many
resources on Python and likely developers in your organization can help you get up to speed.
4.4.4 Ruby
If you are using Ruby for test automation then you probably are already familiar with developing in
Ruby. To add Selenium to your Ruby environment run the following command from a command-line.
gem install selenium-webdriver
Teaching Ruby development itself is beyond the scope of this document, however there are many resources
on Ruby and likely developers in your organization can help you get up to speed.
4.4. Setting Up a Selenium-WebDriver Project 49
Selenium Documentation, Release 1.0
4.4.5 Perl
Perl bindings are provided by a third party, please refer to any of their documentation on how to install /
get started. There is one known Perl binding as of this writing.
4.4.6 PHP
PHP bindings are provided by a third party, please refer to any of their documentation on how to install /
get started. There are three known bindings at this time: By Chibimagic By Lukasz Kolczynski and By
the Facebook
4.5 Migrating from Selenium 1.0
For those who already have test suites written using Selenium 1.0, we have provided tips on how to
migrate your existing code to Selenium 2.0. Simon Stewart, the lead developer for Selenium 2.0, has
written an article on migrating from Selenium 1.0. We’ve included this as an appendix.
Migrating From Selenium RC to Selenium WebDriver
4.6 Introducing the Selenium-WebDriver API by Example
WebDriver is a tool for automating web application testing, and in particular to verify that they work as
expected. It aims to provide a friendly API that’s easy to explore and understand, easier to use than the
Selenium-RC (1.0) API, which will help to make your tests easier to read and maintain. It’s not tied to
any particular test framework, so it can be used equally well in a unit testing or from a plain old “main”
method. This section introduces WebDriver’s API and helps get you started becoming familiar with
it. Start by setting up a WebDriver project if you haven’t already. This was described in the previous
section, Setting Up a Selenium-WebDriver Project.
Once your project is set up, you can see that WebDriver acts just as any normal library: it is entirely
self-contained, and you usually don’t need to remember to start any additional processes or run any
installers before using it, as opposed to the proxy server with Selenium-RC.
Note: additional steps are required to use Chrome Driver, Opera Driver, Android Driver and iPhone
Driver
You’re now ready to write some code. An easy way to get started is this example, which searches for
the term “Cheese” on Google and then outputs the result page’s title to the console.
package org.openqa.selenium.example;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
public class Selenium2Example {
public static void main(String[] args) {
// Create a new instance of the Firefox driver
// Notice that the remainder of the code relies on the interface,
50 Chapter 4. Selenium WebDriver
Selenium Documentation, Release 1.0
// not the implementation.
WebDriver driver = new FirefoxDriver();
// And now use this to visit Google
driver.get( "http://www.google.com" );
// Alternatively the same thing can be done like this
// driver.navigate().to("http://www.google.com");
// Find the text input element by its name
WebElement element = driver.findElement(By.name( "q" ));
// Enter something to search for
element.sendKeys( "Cheese!" );
// Now submit the form. WebDriver will find the form for us from the element
element.submit();
// Check the title of the page
System.out.println( "Page title is: " + driver.getTitle());
// Google’s search is rendered dynamically with JavaScript.
// Wait for the page to load, timeout after 10 seconds
(new WebDriverWait(driver, 10)).until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return d.getTitle().toLowerCase().startsWith( "cheese!" );
}
});
// Should see: "cheese! - Google Search"
System.out.println( "Page title is: " + driver.getTitle());
//Close the browser
driver.quit();
}
}
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
// Requires reference to WebDriver.Support.dll
using OpenQA.Selenium.Support.UI;
class GoogleSuggest
{
static void Main(string[] args)
{
// Create a new instance of the Firefox driver.
// Notice that the remainder of the code relies on the interface,
// not the implementation.
// Further note that other drivers (InternetExplorerDriver,
// ChromeDriver, etc.) will require further configuration
// before this example will work. See the wiki pages for the
// individual drivers at http://code.google.com/p/selenium/wiki
// for further information.
4.6. Introducing the Selenium-WebDriver API by Example 51
Selenium Documentation, Release 1.0
IWebDriver driver = new FirefoxDriver();
//Notice navigation is slightly different than the Java version
//This is because ’get’ is a keyword in C#
driver.Navigate().GoToUrl( "http://www.google.com/" );
// Find the text input element by its name
IWebElement query = driver.FindElement(By.Name( "q" ));
// Enter something to search for
query.SendKeys( "Cheese" );
// Now submit the form. WebDriver will find the form for us from the element
query.Submit();
// Google’s search is rendered dynamically with JavaScript.
// Wait for the page to load, timeout after 10 seconds
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until((d) => { return d.Title.ToLower().StartsWith( "cheese" ); });
// Should see: "Cheese - Google Search"
System.Console.WriteLine( "Page title is: " + driver.Title);
//Close the browser
driver.Quit();
}
}
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
import time
# Create a new instance of the Firefox driver
driver = webdriver.Firefox()
# go to the google home page
driver.get( " http://www.google.com " )
# find the element that’s name attribute is q (the google search box)
inputElement = driver.find_element_by_name( " q " )
# type in the search
inputElement.send_keys( " Cheese! " )
# submit the form (although google automatically searches now without submitting)
inputElement.submit()
# the page is ajaxy so the title is originally this:
print driver.title
try:
# we have to wait for the page to refresh, the last thing that seems to be updated is WebDriverWait(driver, 10).until(lambda driver : driver.title.lower().startswith( " cheese! # You should see "cheese! - Google Search"
52 Chapter 4. Selenium WebDriver
Selenium Documentation, Release 1.0
print driver.title
finally:
driver.quit()
require ’rubygems’
require ’selenium-webdriver’
driver = Selenium::WebDriver.for :firefox
driver.get " http://google.com "
element = driver.find_element :name => " q "
element.send_keys " Cheese! "
element.submit
puts " Page title is #{ driver.title } "
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until { driver.title.downcase.start_with? " cheese! " }
puts " Page title is #{ driver.title } "
driver.quit
In upcoming sections, you will learn more about how to use WebDriver for things such as navigating
forward and backward in your browser’s history, and how to test web sites that use frames and windows.
We also provide a more thorough discussions and examples.
4.7 Selenium-WebDriver API Commands and Operations
4.7.1 Fetching a Page
The first thing you’re likely to want to do with WebDriver is navigate to a page. The normal way to do
this is by calling “get”:
driver.get( "http://www.google.com" );
driver.Url = "http://www.google.com" ;
driver.get " http://www.google.com "
driver.get( " http://www.google.com " )
Dependent on several factors, including the OS/Browser combination, WebDriver may or may not wait
for the page to load. In some circumstances,WebDriver may return control before the page has finished,
or even started, loading. To ensure robustness, you need to wait for the element(s) to exist in the page
using Explicit and Implicit Waits.
4.7. Selenium-WebDriver API Commands and Operations 53
Selenium Documentation, Release 1.0
4.7.2 Locating UI Elements (WebElements)
Locating elements in WebDriver can be done on the WebDriver instance itself or on a WebElement.
Each of the language bindings expose a “Find Element” and “Find Elements” method. The first returns
a WebElement object otherwise it throws an exception. The latter returns a list of WebElements, it can
return an empty list if no DOM elements match the query.
The “Find” methods take a locator or query object called “By”. “By” strategies are listed below.
By ID
This is the most efficient and preferred way to locate an element. Common pitfalls that UI developers
make is having non-unique id’s on a page or auto-generating the id, both should be avoided. A class on
an html element is more appropriate than an auto-generated id.
Example of how to find an element that looks like this:
<div id= "coolestWidgetEvah" >...</div>
WebElement element = driver.findElement(By.id( "coolestWidgetEvah" ));
IWebElement element = driver.FindElement(By.Id( "coolestWidgetEvah" ));
element = driver.find_element(:id, " coolestWidgetEvah " )
element = driver.find_element_by_id("coolestWidgetEvah")
or
from selenium.webdriver.common.by import By
element = driver.find_element(by=By.ID, value="coolestWidgetEvah")
By Class Name
“Class” in this case refers to the attribute on the DOM element. Often in practical use there are many
DOM elements with the same class name, thus finding multiple elements becomes the more practical
option over finding the first element.
Example of how to find an element that looks like this:
<div class= "cheese" ><span>Cheddar</span></div><div class= "cheese" ><span>Gouda</span></List<WebElement> cheeses = driver.findElements(By.className( "cheese" ));
IList<IWebElement> cheeses = driver.FindElements(By.ClassName( "cheese" ));
54 Chapter 4. Selenium WebDriver
Selenium Documentation, Release 1.0
cheeses = driver.find_elements(:class_name, " cheese " )
or
cheeses = driver.find_elements(:class, " cheese " )
cheeses = driver.find_elements_by_class_name("cheese")
or
from selenium.webdriver.common.by import By
cheeses = driver.find_elements(By.CLASS_NAME, "cheese")
By Tag Name
The DOM Tag Name of the element.
Example of how to find an element that looks like this:
<iframe src= "..." ></iframe>
WebElement frame = driver.findElement(By.tagName( "iframe" ));
IWebElement frame = driver.FindElement(By.TagName( "iframe" ));
frame = driver.find_element(:tag_name, " iframe " )
frame = driver.find_element_by_tag_name("iframe")
or
from selenium.webdriver.common.by import By
frame = driver.find_element(By.TAG_NAME, "iframe")
By Name
Find the input element with matching name attribute.
Example of how to find an element that looks like this:
<input name= "cheese" type= "text" />
WebElement cheese = driver.findElement(By.name( "cheese" ));
4.7. Selenium-WebDriver API Commands and Operations 55
Selenium Documentation, Release 1.0
IWebElement cheese = driver.FindElement(By.Name( "cheese" ));
cheese = driver.find_element(:name, " cheese " )
cheese = driver.find_element_by_name("cheese")
or
from selenium.webdriver.common.by import By
cheese = driver.find_element(By.NAME, "cheese")
By Link Text
Find the link element with matching visible text.
Example of how to find an element that looks like this:
<a href= "http://www.google.com/search?q=cheese" >cheese</a>>
WebElement cheese = driver.findElement(By.linkText( "cheese" ));
IWebElement cheese = driver.FindElement(By.LinkText( "cheese" ));
cheese = driver.find_element(:link_text, " cheese " )
or
cheese = driver.find_element(:link, " cheese " )
cheese = driver.find_element_by_link_text("cheese")
or
from selenium.webdriver.common.by import By
cheese = driver.find_element(By.LINK_TEXT, "cheese")
By Partial Link Text
Find the link element with partial matching visible text.
Example of how to find an element that looks like this:
<a href= "http://www.google.com/search?q=cheese" >search for cheese</a>>
56 Chapter 4. Selenium WebDriver
Selenium Documentation, Release 1.0
WebElement cheese = driver.findElement(By.partialLinkText( "cheese" ));
IWebElement cheese = driver.FindElement(By.PartialLinkText( "cheese" ));
cheese = driver.find_element(:partial_link_text, " cheese " )
cheese = driver.find_element_by_partial_link_text("cheese")
or
from selenium.webdriver.common.by import By
cheese = driver.find_element(By.PARTIAL_LINK_TEXT, "cheese")
By CSS
Like the name implies it is a locator strategy by css. Native browser support is used by default, so please
refer to w3c css selectors <http://www.w3.org/TR/CSS/#selectors> for a list of generally available css
selectors. If a browser does not have native support for css queries, then Sizzle is used. IE 6,7 and FF3.0
currently use Sizzle as the css query engine.
Beware that not all browsers were created equal, some css that might work in one version may not work
in another.
Example of to find the cheese below:
<div id= "food" ><span class= "dairy" >milk</span><span class= "dairy aged" >cheese</span></WebElement cheese = driver.findElement(By.cssSelector( "#food span.dairy.aged" ));
IWebElement cheese = driver.FindElement(By.CssSelector( "#food span.dairy.aged" ));
cheese = driver.find_element(:css, " # food span.dairy.aged " )
cheese = driver.find_element_by_css_selector("#food span.dairy.aged")
or
from selenium.webdriver.common.by import By
cheese = driver.find_element(By.CSS_SELECTOR, "#food span.dairy.aged")
4.7. Selenium-WebDriver API Commands and Operations 57
Selenium Documentation, Release 1.0
By XPATH
At a high level, WebDriver uses a browser’s native XPath capabilities wherever possible. On those
browsers that don’t have native XPath support, we have provided our own implementation. This can
lead to some unexpected behaviour unless you are aware of the differences in the various xpath engines.
Driver Tag and Attribute
Name
Attribute Values Native XPath
Support
HtmlUnit Driver Lower-cased As they appear in the
HTML
Yes
Internet Explorer
Driver
Lower-cased As they appear in the
HTML
No
Firefox Driver Case insensitive As they appear in the
HTML
Yes
This is a little abstract, so for the following piece of HTML:
<input type= "text" name= "example" />
<INPUT type= "text" name= "other" />
List<WebElement> inputs = driver.findElements(By.xpath( "//input" ));
IList<IWebElement> inputs = driver.FindElements(By.XPath( "//input" ));
inputs = driver.find_elements(:xpath, " //input " )
inputs = driver.find_elements_by_xpath("//input")
or
from selenium.webdriver.common.by import By
inputs = driver.find_elements(By.XPATH, "//input")
The following number of matches will be found
XPath expression HtmlUnit Driver Firefox Driver Internet Explorer Driver
//input 1 (“example”) 2 2
//INPUT 0 2 0
Sometimes HTML elements do not need attributes to be explicitly declared because they will default to
known values. For example, the “input” tag does not require the “type” attribute because it defaults to
“text”. The rule of thumb when using xpath in WebDriver is that you should not expect to be able to
match against these implicit attributes.
Using JavaScript
You can execute arbitrary javascript to find an element and as long as you return a DOM Element, it will
be automatically converted to a WebElement object.
Simple example on a page that has jQuery loaded:
58 Chapter 4. Selenium WebDriver
Selenium Documentation, Release 1.0
WebElement element = (WebElement) ((JavascriptExecutor)driver).executeScript( "return $(’.IWebElement element = (IWebElement) ((IJavaScriptExecutor)driver).ExecuteScript( "return element = driver.execute_script( " return $(’.cheese’)[0] " )
element = driver.execute_script( " return $( ’ .cheese ’ )[0] " )
Finding all the input elements to the every label on a page:
List<WebElement> labels = driver.findElements(By.tagName( "label" ));
List<WebElement> inputs = (List<WebElement>) ((JavascriptExecutor)driver).executeScript(
"var labels = arguments[0], inputs = []; for (var i=0; i < labels.length; i++){" +
"inputs.push(document.getElementById(labels[i].getAttribute(’for’))); } return inputs;" IList<IWebElement> labels = driver.FindElements(By.TagName( "label" ));
IList<IWebElement> inputs = (IList<IWebElement>) ((IJavaScriptExecutor)driver).ExecuteScript(
"var labels = arguments[0], inputs = []; for (var i=0; i < labels.length; i++){" +
"inputs.push(document.getElementById(labels[i].getAttribute(’for’))); } return inputs;" labels = driver.find_elements(:tag_name, " label " )
inputs = driver.execute_script(
" var labels = arguments[0], inputs = []; for (var i=0; i < labels.length; i++){ " " inputs.push(document.getElementById(labels[i].getAttribute(’for’))); } return inputs; labels = driver.find_elements_by_tag_name( " label " )
inputs = driver.execute_script(
" var labels = arguments[0], inputs = []; for (var i=0; i < labels.length; i++){ " " inputs.push(document.getElementById(labels[i].getAttribute( ’ for ’ ))); } return 4.7.3 User Input - Filling In Forms
We’ve already seen how to enter text into a textarea or text field, but what about the other elements?
You can “toggle” the state of checkboxes, and you can use “click” to set something like an OPTION tag
selected. Dealing with SELECT tags isn’t too bad:
WebElement select = driver.findElement(By.tagName( "select" ));
List<WebElement> allOptions = select.findElements(By.tagName( "option" ));
for (WebElement option : allOptions) {
System.out.println(String.format( "Value is: %s" , option.getAttribute( "value" )));
option.click();
}
4.7. Selenium-WebDriver API Commands and Operations 59
Selenium Documentation, Release 1.0
IWebElement select = driver.FindElement(By.TagName( "select" ));
IList<IWebElement> allOptions = select.FindElements(By.TagName( "option" ));
foreach (IWebElement option in allOptions)
{
System.Console.WriteLine( "Value is: " + option.GetAttribute( "value" ));
option.Click();
}
select = driver.find_element(:tag_name, " select " )
all_options = select.find_elements(:tag_name, " option " )
all_options.each do |option|
puts " Value is: " + option.attribute( " value " )
option.click
end
select = driver.find_element_by_tag_name( " select " )
allOptions = select.find_elements_by_tag_name( " option " )
for option in allOptions:
print " Value is: " + option.get_attribute( " value " )
option.click()
This will find the first “SELECT” element on the page, and cycle through each of its OPTIONs in turn,
printing out their values, and selecting each in turn. As you will notice, this isn’t the most efficient
way of dealing with SELECT elements. WebDriver’s support classes include one called “Select”, which
provides useful methods for interacting with these.
Select select = new Select(driver.findElement(By.tagName( "select" )));
select.deselectAll();
select.selectByVisibleText( "Edam" );
SelectElement select = new SelectElement(driver.FindElement(By.TagName( "select" )));
select.DeselectAll();
select.SelectByText( "Edam" );
# available since 2.14
select = Selenium::WebDriver::Support::Select.new(driver.find_element(:tag_name, " select select.deselect_all()
select.select_by(:text, " Edam " )
# available since 2.12
from selenium.webdriver.support.ui import Select
select = Select(driver.find_element_by_tag_name( " select " ))
select.deselect_all()
select.select_by_visible_text( " Edam " )
This will deselect all OPTIONs from the first SELECT on the page, and then select the OPTION with
the displayed text of “Edam”.
Once you’ve finished filling out the form, you probably want to submit it. One way to do this would be
to find the “submit” button and click it:
60 Chapter 4. Selenium WebDriver
Selenium Documentation, Release 1.0
driver.findElement(By.id( "submit" )).click();
driver.find_element(:id, " submit " ).click
driver.find_element_by_id( " submit " ).click()
Alternatively, WebDriver has the convenience method “submit” on every element. If you call this on an
element within a form, WebDriver will walk up the DOM until it finds the enclosing form and then calls
submit on that. If the element isn’t in a form, then the NoSuchElementException will be thrown:
element.submit();
element.submit
element.submit()
4.7.4 Moving Between Windows and Frames
Some web applications have many frames or multiple windows. WebDriver supports moving between
named windows using the “switchTo” method:
driver.switchTo().window( "windowName" );
driver.switch_to_window( " windowName " )
All calls to driver will now be interpreted as being directed to the particular window. But how do you
know the window’s name? Take a look at the javascript or link that opened it:
<a href= "somewhere.html" target= "windowName" >Click here to open a new window</a>
Alternatively, you can pass a “window handle” to the “switchTo().window()” method. Knowing this, it’s
possible to iterate over every open window like so:
for (String handle : driver.getWindowHandles()) {
driver.switchTo().window(handle);
}
driver.window_handles.each do |handle|
driver.switch_to.window handle
end
for handle in driver.window_handles:
driver.switch_to_window(handle)
You can also switch from frame to frame (or into iframes):
4.7. Selenium-WebDriver API Commands and Operations 61
Selenium Documentation, Release 1.0
driver.switchTo().frame( "frameName" );
driver.switch_to_frame( " frameName " )
It’s possible to access subframes by separating the path with a dot, and you can specify the frame by its
index too. That is:
driver.switchTo().frame( "frameName.0.child" );
driver.switch_to_frame( " frameName.0.child " )
would go to the frame named “child” of the first subframe of the frame called “frameName”. All frames
are evaluated as if from *top*.
4.7.5 Popup Dialogs
Starting with Selenium 2.0 beta 1, there is built in support for handling popup dialog boxes. After you’ve
triggered an action that opens a popup, you can access the alert with the following:
Alert alert = driver.switchTo().alert();
alert = driver.switch_to.alert
alert = driver.switch_to_alert()
# usage: alert.dismiss(), etc.
This will return the currently open alert object. With this object you can now accept, dismiss, read its
contents or even type into a prompt. This interface works equally well on alerts, confirms, and prompts.
Refer to the JavaDocs or RubyDocs for more information.
4.7.6 Navigation: History and Location
Earlier, we covered navigating to a page using the “get” command (
driver.get("http://www.example.com")) As you’ve seen, WebDriver has a number
of smaller, task-focused interfaces, and navigation is a useful task. Because loading a page is such a
fundamental requirement, the method to do this lives on the main WebDriver interface, but it’s simply a
synonym to:
driver.navigate().to( "http://www.example.com" );
driver.navigate.to " http://www.example.com "
driver.get( " http://www.example.com " ) # python doesn’t have driver.navigate
62 Chapter 4. Selenium WebDriver
Selenium Documentation, Release 1.0
To reiterate: “navigate().to()” and “get()” do exactly the same thing. One’s just a lot easier to
type than the other!
The “navigate” interface also exposes the ability to move backwards and forwards in your browser’s
history:
driver.navigate().forward();
driver.navigate().back();
driver.navigate.forward
driver.navigate.back
driver.forward()
driver.back()
Please be aware that this functionality depends entirely on the underlying browser. It’s just possible that
something unexpected may happen when you call these methods if you’re used to the behaviour of one
browser over another.
4.7.7 Cookies
Before we leave these next steps, you may be interested in understanding how to use cookies. First of
all, you need to be on the domain that the cookie will be valid for. If you are trying to preset cookies
before you start interacting with a site and your homepage is large / takes a while to load an alternative
is to find a smaller page on the site, typically the 404 page is small (http://example.com/some404page)
// Go to the correct domain
driver.get( "http://www.example.com" );
// Now set the cookie. This one’s valid for the entire domain
Cookie cookie = new Cookie( "key" , "value" );
driver.manage().addCookie(cookie);
// And now output all the available cookies for the current URL
Set<Cookie> allCookies = driver.manage().getCookies();
for (Cookie loadedCookie : allCookies) {
System.out.println(String.format( "%s -> %s" , loadedCookie.getName(), loadedCookie.getValue()));
}
// You can delete cookies in 3 ways
// By name
driver.manage().deleteCookieNamed( "CookieName" );
// By Cookie
driver.manage().deleteCookie(loadedCookie);
// Or all of them
driver.manage().deleteAllCookies();
# Go to the correct domain
driver.get( " http://www.example.com " )
# Now set the cookie. Here’s one for the entire domain
# the cookie name here is ’key’ and it’s value is ’value’
driver.add_cookie({ ’ name ’ : ’ key ’ , ’ value ’ : ’ value ’ , ’ path ’ : ’ / ’ })
4.7. Selenium-WebDriver API Commands and Operations 63
Selenium Documentation, Release 1.0
# additional keys that can be passed in are:
# ’domain’ -> String, ’secure’ -> Boolean,
# ’expiry’ -> Milliseconds since the Epoch it should expire.
# And now output all the available cookies for the current URL
for cookie in driver.get_cookies():
print " %s -> %s " % (cookie[ ’ name ’ ], cookie[ ’ value ’ ])
# You can delete cookies in 2 ways
# By name
driver.delete_cookie( " CookieName " )
# Or all of them
driver.delete_all_cookies()
# Go to the correct domain
driver.get " http://www.example.com "
# Now set the cookie. Here’s one for the entire domain
# the cookie name here is ’key’ and it’s value is ’value’
driver.manage.add_cookie(:name => ’key’ , :value => ’value’ )
# additional keys that can be passed in are:
# :path => String, :secure -> Boolean, :expires -> Time, DateTime, or seconds since epoch
# And now output all the available cookies for the current URL
driver.manage.all_cookies.each { |cookie|
puts " #{ cookie[:name] } => #{ cookie[:value] } "
}
# You can delete cookies in 2 ways
# By name
driver.manage.delete_cookie( " CookieName " )
# Or all of them
driver.manage.delete_all_cookies
4.7.8 Changing the User Agent
This is easy with the Firefox Driver:
FirefoxProfile profile = new FirefoxProfile();
profile.addAdditionalPreference( "general.useragent.override" , "some UA string" );
WebDriver driver = new FirefoxDriver(profile);
profile = Selenium::WebDriver::Firefox::Profile.new
profile[ ’general.useragent.override’ ] = " some UA string "
driver = Selenium::WebDriver.for :firefox, :profile => profile
4.7.9 Drag And Drop
Here’s an example of using the Actions class to perform a drag and drop. Native events are required to
be enabled.
64 Chapter 4. Selenium WebDriver
Selenium Documentation, Release 1.0
WebElement element = driver.findElement(By.name( "source" ));
WebElement target = driver.findElement(By.name( "target" ));
(new Actions(driver)).dragAndDrop(element, target).perform();
element = driver.find_element(:name => ’source’ )
target = driver.find_element(:name => ’target’ )
driver.action.drag_and_drop(element, target).perform
from selenium.webdriver.common.action_chains import ActionChains
element = driver.find_element_by_name( " source " )
target = driver.find_element_by_name( " target " )
ActionChains(driver).drag_and_drop(element, target).perform()
4.8 Driver Specifics and Tradeoffs
4.9 Selenium-WebDriver’s Drivers
WebDriver is the name of the key interface against which tests should be written, but there are several
implementations. These include:
4.9.1 HtmlUnit Driver
This is currently the fastest and most lightweight implementation of WebDriver. As the name suggests,
this is based on HtmlUnit. HtmlUnit is a java based implementation of a WebBrowser without a GUI.
For any language binding (other than java) the Selenium Server is required to use this driver.
Usage
WebDriver driver = new HtmlUnitDriver();
IWebDriver driver = new RemoteWebDriver(new Uri( "http://127.0.0.1:4444/wd/hub" ),
DesiredCapabilities.HtmlUnit());
driver = webdriver.Remote( " http://localhost:4444/wd/hub " , webdriver.DesiredCapabilities.driver = Selenium::WebDriver.for :remote, :url => " http://localhost:4444/wd/hub " , :desired_4.8. Driver Specifics and Tradeoffs 65
Selenium Documentation, Release 1.0
Pros
• Fastest implementation of WebDriver
• A pure Java solution and so it is platform independent.
• Supports JavaScript
Cons
• Emulates other browsers’ JavaScript behaviour (see below)
JavaScript in the HtmlUnit Driver
None of the popular browsers uses the JavaScript engine used by HtmlUnit (Rhino). If you test
JavaScript using HtmlUnit the results may differ significantly from those browsers.
When we say “JavaScript” we actually mean “JavaScript and the DOM”. Although the DOM is defined
by the W3C each browser has its own quirks and differences in their implementation of the DOM and
in how JavaScript interacts with it. HtmlUnit has an impressively complete implementation of the DOM
and has good support for using JavaScript, but it is no different from any other browser: it has its
own quirks and differences from both the W3C standard and the DOM implementations of the major
browsers, despite its ability to mimic other browsers.
With WebDriver, we had to make a choice; do we enable HtmlUnit’s JavaScript capabilities and run
the risk of teams running into problems that only manifest themselves there, or do we leave JavaScript
disabled, knowing that there are more and more sites that rely on JavaScript? We took the conservative
approach, and by default have disabled support when we use HtmlUnit. With each release of both
WebDriver and HtmlUnit, we reassess this decision: we hope to enable JavaScript by default on the
HtmlUnit at some point.
Enabling JavaScript
If you can’t wait, enabling JavaScript support is very easy:
HtmlUnitDriver driver = new HtmlUnitDriver(true);
WebDriver driver = new RemoteWebDriver(new Uri( "http://127.0.0.1:4444/wd/hub" ),
DesiredCapabilities.HtmlUnitWithJavaScript());
caps = Selenium::WebDriver::Remote::Capabilities.htmlunit(:javascript_enabled => true)
driver = Selenium::WebDriver.for :remote, :url => " http://localhost:4444/wd/hub " , :desired_driver = webdriver.Remote( " http://localhost:4444/wd/hub " , webdriver.DesiredCapabilities.This will cause the HtmlUnit Driver to emulate Firefox 3.6’s JavaScript handling by default.
66 Chapter 4. Selenium WebDriver
Selenium Documentation, Release 1.0
4.9.2 Firefox Driver
Controls the Firefox browser using a Firefox plugin. The Firefox Profile that is used is stripped down
from what is installed on the machine to only include the Selenium WebDriver.xpi (plugin). A few
settings are also changed by default (see the source to see which ones) Firefox Driver is capable of being
run and is tested on Windows, Mac, Linux. Currently on versions 3.0, 3.6, 5, 6, 7, and 8
Usage
WebDriver driver = new FirefoxDriver();
IWebDriver driver = new FirefoxDriver();
driver = webdriver.Firefox()
driver = Selenium::WebDriver.for :firefox
Pros
• Runs in a real browser and supports JavaScript
• Faster than the Internet Explorer Driver
Cons
• Slower than the HtmlUnit Driver
Modifying the Firefox Profile
Suppose that you wanted to modify the user agent string (as above), but you’ve got a tricked out Firefox
profile that contains dozens of useful extensions. There are two ways to obtain this profile. Assuming
that the profile has been created using Firefox’s profile manager (firefox -ProfileManager):
ProfileIni allProfiles = new ProfilesIni();
FirefoxProfile profile = allProfiles.getProfile( "WebDriver" );
profile.setPreferences( "foo.bar" , 23);
WebDriver driver = new FirefoxDriver(profile);
Alternatively, if the profile isn’t already registered with Firefox:
File profileDir = new File( "path/to/top/level/of/profile" );
FirefoxProfile profile = new FirefoxProfile(profileDir);
profile.addAdditionalPreferences(extraPrefs);
WebDriver driver = new FirefoxDriver(profile);
As we develop features in the Firefox Driver, we expose the ability to use them. For example, until we
feel native events are stable on Firefox for Linux, they are disabled by default. To enable them:
4.9. Selenium-WebDriver’s Drivers 67
Selenium Documentation, Release 1.0
FirefoxProfile profile = new FirefoxProfile();
profile.setEnableNativeEvents(true);
WebDriver driver = new FirefoxDriver(profile);
profile = Selenium::WebDriver::Firefox::Profile.new
profile.native_events = true
driver = Selenium::WebDriver.for :firefox, :profile => profile
Info
See the Firefox section in the wiki page for the most up to date info.
4.9.3 Internet Explorer Driver
This driver is controlled by a .dll and is thus only available on Windows OS. Each Selenium release has
it’s core functionality tested against versions 6, 7 and 8 on XP, and 9 on Windows7.
Usage
WebDriver driver = new InternetExplorerDriver();
IWebDriver driver = new InternetExlorerDriver();
driver = webdriver.Ie()
driver = Selenium::WebDriver.for :ie
Pros
• Runs in a real browser and supports JavaScript with all the quirks your end users see.
Cons
• Obviously the Internet Explorer Driver will only work on Windows!
• Comparatively slow (though still pretty snappy :)
• XPath is not natively supported in most versions. Sizzle is injected automatically which is significantly
slower than other browsers and slower when comparing to CSS selectors in the same
browser.
• CSS is not natively supported in versions 6 and 7. Sizzle is injected instead.
• CSS selectors in IE 8 and 9 are native, but those browsers don’t fully support CSS3
68 Chapter 4. Selenium WebDriver
Selenium Documentation, Release 1.0
Info
See the Internet Explorer section of the wiki page for the most up to date info. Please take special note
of the Required Configuration section.
4.9.4 Chrome Driver
Chrome Driver is maintained / supported by the Chromium project iteslf. WebDriver works with Chrome
through the chromedriver binary (found on the chromium project’s download page). You need to have
both chromedriver and a version of chrome browser installed. chromedriver needs to be placed somewhere
on your system’s path in order for WebDriver to automatically discover it. The Chrome browser
itself is discovered by chromedriver in the default installation path. These both can be overridden by
environment variables. Please refer to the wiki for more information.
Usage
WebDriver driver = new ChromeDriver();
IWebDriver driver = new ChromeDriver();
driver = webdriver.Chrome()
driver = Selenium::WebDriver.for :chrome
Pros
• Runs in a real browser and supports JavaScript
• Because Chrome is aWebkit-based browser, the Chrome Driver may allow you to verify that your
site works in Safari. Note that since Chrome uses its own V8 JavaScript engine rather than Safari’s
Nitro engine, JavaScript execution may differ.
Cons
• Slower than the HtmlUnit Driver
Info
See our wiki for the most up to date info. More info can also be found on the downloads page
Getting running with Chrome Driver
Download the Chrome Driver executable and follow the other instructions on the wiki page
4.9. Selenium-WebDriver’s Drivers 69
Selenium Documentation, Release 1.0
4.9.5 Opera Driver
See the Opera Driver wiki article in the Selenium Wiki for information on using the Opera Driver.
4.9.6 iPhone Driver
See the iPhone Driver wiki article in the Selenium Wiki for information on using the Mac iOS Driver.
4.9.7 Android Driver
See the Android Driver wiki article in the Selenium Wiki for information on using the Android Driver.
4.10 Alternative Back-Ends: Mixing WebDriver and RC Technologies
4.10.1 WebDriver-Backed Selenium-RC
The Java version of WebDriver provides an implementation of the Selenium-RC API. These means
that you can use the underlying WebDriver technology using the Selenium-RC API. This is primarily
provided for backwards compatibility. It allows those who have existing test suites using the Selenium-
RC API to use WebDriver under the covers. It’s provided to help ease the migration path to Selenium-
WebDriver. Also, this allows one to use both APIs, side-by-side, in the same test code.
Selenium-WebDriver is used like this:
// You may use any WebDriver implementation. Firefox is used here as an example
WebDriver driver = new FirefoxDriver();
// A "base url", used by selenium to resolve relative URLs
String baseUrl = "http://www.google.com" ;
// Create the Selenium implementation
Selenium selenium = new WebDriverBackedSelenium(driver, baseUrl);
// Perform actions with selenium
selenium.open( "http://www.google.com" );
selenium.type( "name=q" , "cheese" );
selenium.click( "name=btnG" );
// Get the underlying WebDriver implementation back. This will refer to the
// same WebDriver instance as the "driver" variable above.
WebDriver driverInstance = ((WebDriverBackedSelenium) selenium).getWrappedDriver();
//Finally, close the browser. Call stop on the WebDriverBackedSelenium instance
//instead of calling driver.quit(). Otherwise, the JVM will continue running after
//the browser has been closed.
selenium.stop();
70 Chapter 4. Selenium WebDriver
Selenium Documentation, Release 1.0
Pros
• Allows for the WebDriver and Selenium APIs to live side-by-side
• Provides a simple mechanism for a managed migration from the Selenium RC API toWebDriver’s
• Does not require the standalone Selenium RC server to be run
Cons
• Does not implement every method
• More advanced Selenium usage (using “browserbot” or other built-in JavaScript methods from
Selenium Core) may not work
• Some methods may be slower due to underlying implementation differences
4.10.2 Backing WebDriver with Selenium
WebDriver doesn’t support as many browsers as Selenium RC does, so in order to provide that support
while still using the WebDriver API, you can make use of the SeleneseCommandExecutor
Safari is supported in this way with the following code (be sure to disable pop-up blocking):
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setBrowserName( "safari" );
CommandExecutor executor = new SeleneseCommandExecutor(new URL( "http://localhost:4444/" WebDriver driver = new RemoteWebDriver(executor, capabilities);
There are currently some major limitations with this approach, notably that findElements doesn’t work
as expected. Also, because we’re using Selenium Core for the heavy lifting of driving the browser, you
are limited by the JavaScript sandbox.
4.11 Additional Resources
You can find further resources for WebDriver in WebDriver’s wiki
Of course, don’t hesitate to do an internet search on any Selenium topic, including Selenium-
WebDriver’s drivers. There are quite a few blogs on Selenium along with numerous posts
on various user forums. Additionally the Selenium User’s Group is a great resource.
http://groups.google.com/group/selenium-users
4.12 Next Steps
This chapter has simply been a high level walkthrough of WebDriver and some of its key capabilities.
Once getting familiar with the Selenium-WebDriver API you will then want to learn how to build
test suites for maintainability, extensibility, and reduced fragility when features of the AUT frequently
change. The approach most Selenium experts are now recommending is to design your test code using
the Page Object Design Pattern along with possibly a Page Factory. Selenium-WebDriver provides
support for this by supplying a PageFactory class in Java and C#. This is presented,along with other
advanced topics, in the next chapter. Also, for high-level description of this technique, you may want
4.11. Additional Resources 71
Selenium Documentation, Release 1.0
to look at the Test Design Considerations chapter. Both of these chapters present techniques for writing
more maintainable tests by making your test code more modular.
72 Chapter 4. Selenium WebDriver
CHAPTER
FIVE
WEBDRIVER: ADVANCED USAGE
5.1 Explicit and Implicit Waits
Waiting is having the automated task execution elapse a certain amount of time before continuing with
the next step.
5.1.1 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()
73
Selenium Documentation, Release 1.0
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 waits up to 10 seconds before throwing a TimeoutException or if it finds the element will return it
in 0 - 10 seconds. WebDriverWait by default calls the ExpectedCondition every 500 milliseconds until
it returns successfully. A successful return is for ExpectedCondition type is Boolean return true or not
null return value for all other ExpectedCondition types.
This example is also functionally equivalent to the first Implicit Waits example.
The ExpectedConditions class in contains a set of predefined conditions to use with WebDriverWait in
Java.
5.1.2 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
74 Chapter 5. WebDriver: Advanced Usage
Selenium Documentation, Release 1.0
driver.manage.timeouts.implicit_wait = 10 # seconds
driver.get " http://somedomain/url_that_delays_loading "
element = driver.find_element(:id => " some-dynamic-element " )
5.2 RemoteWebDriver
5.2.1 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 /// </summary>
/// <returns>A <see cref="Screenshot"/> object containing the image.</returns>
public Screenshot GetScreenshot()
5.2. RemoteWebDriver 75
Selenium Documentation, Release 1.0
{
// 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:// ... 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.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 " , :driver.get " http://www.google.com "
driver.save_screenshot " /Screenshots/google.png "
ensure
driver.quit
end
5.3 AdvancedUserInteractions
Todo
5.4 Browser Startup Manipulation
Todo
Topics to be included:
• restoring cookies
• changing firefox profile
76 Chapter 5. WebDriver: Advanced Usage
Selenium Documentation, Release 1.0
• running browsers with plugins
5.4.1 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.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)
5.4. Browser Startup Manipulation 77
Selenium Documentation, Release 1.0
# 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_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’
78 Chapter 5. WebDriver: Advanced Usage
Selenium Documentation, Release 1.0
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
Opera
Todo
5.5 HTML5
Todo
5.6 Parallelizing Your Test Runs
Todo
5.5. HTML5 79
Selenium Documentation, Release 1.0
80 Chapter 5. WebDriver: Advanced Usage
CHAPTER
SIX
SELENIUM 1 (SELENIUM RC)
6.1 Introduction
As you can read in Brief History of The Selenium Project, Selenium RC was the main Selenium project
for a long time, before the WebDriver/Selenium merge brought up Selenium 2, the newest and more
powerful tool.
Selenium 1 is still actively supported (mostly in maintenance mode) and provides some features that
may not be available in Selenium 2 for a while, including support for several languages (Java, Javascript,
Ruby, PHP, Python, Perl and C#) and support for almost every browser out there.
6.2 How Selenium RC Works
First, we will describe how the components of Selenium RC operate and the role each plays in running
your test scripts.
6.2.1 RC Components
Selenium RC components are:
• The Selenium Server which launches and kills browsers, interprets and runs the Selenese commands
passed from the test program, and acts as an HTTP proxy, intercepting and verifying HTTP
messages passed between the browser and the AUT.
• Client libraries which provide the interface between each programming language and the Selenium
RC Server.
Here is a simplified architecture diagram....
81
Selenium Documentation, Release 1.0
The diagram shows the client libraries communicate with the Server passing each Selenium command
for execution. Then the server passes the Selenium command to the browser using Selenium-Core
JavaScript commands. The browser, using its JavaScript interpreter, executes the Selenium command.
This runs the Selenese action or verification you specified in your test script.
6.2.2 Selenium Server
Selenium Server receives Selenium commands from your test program, interprets them, and reports back
to your program the results of running those tests.
The RC server bundles Selenium Core and automatically injects it into the browser. This occurs when
your test program opens the browser (using a client library API function). Selenium-Core is a JavaScript
program, actually a set of JavaScript functions which interprets and executes Selenese commands using
the browser’s built-in JavaScript interpreter.
The Server receives the Selenese commands from your test program using simple HTTP GET/POST
requests. This means you can use any programming language that can send HTTP requests to automate
Selenium tests on the browser.
82 Chapter 6. Selenium 1 (Selenium RC)
Selenium Documentation, Release 1.0
6.2.3 Client Libraries
The client libraries provide the programming support that allows you to run Selenium commands from a
program of your own design. There is a different client library for each supported language. A Selenium
client library provides a programming interface (API), i.e., a set of functions, which run Selenium commands
from your own program. Within each interface, there is a programming function that supports
each Selenese command.
The client library takes a Selenese command and passes it to the Selenium Server for processing a
specific action or test against the application under test (AUT). The client library also receives the result
of that command and passes it back to your program. Your program can receive the result and store it
into a program variable and report it as a success or failure, or possibly take corrective action if it was
an unexpected error.
So to create a test program, you simply write a program that runs a set of Selenium commands using a
client library API. And, optionally, if you already have a Selenese test script created in the Selenium-
IDE, you can generate the Selenium RC code. The Selenium-IDE can translate (using its Export menu
item) its Selenium commands into a client-driver’s API function calls. See the Selenium-IDE chapter
for specifics on exporting RC code from Selenium-IDE.
6.3 Installation
Installation is rather a misnomer for Selenium. Selenium has set of libraries available in the programming
language of your choice. You could download them from downloads page
Once you’ve chosen a language to work with, you simply need to:
• Install the Selenium RC Server.
• Set up a programming project using a language specific client driver.
6.3.1 Installing Selenium Server
The Selenium RC server is simply a Java jar file (selenium-server-standalone-<version-number>.jar),
which doesn’t require any special installation. Just downloading the zip file and extracting the server in
the desired directory is sufficient.
6.3.2 Running Selenium Server
Before starting any tests you must start the server. Go to the directory where Selenium RC’s server is
located and run the following from a command-line console.
java -jar selenium-server-standalone-<version-number>.jar
This can be simplified by creating a batch or shell executable file (.bat on Windows and .sh on Linux)
containing the command above. Then make a shortcut to that executable on your desktop and simply
double-click the icon to start the server.
For the server to run you’ll need Java installed and the PATH environment variable correctly configured
to run it from the console. You can check that you have Java correctly installed by running the following
on a console.