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.
This could be one of the most useful blogs I have ever come across on this technology. I am a newbie to this technology. Great work admin.
ReplyDeleteSelenium Training in Chennai
software testing selenium training
Loadrunner classes in Chennai
performance testing training in chennai
Qtp classes in chennai
qtp training institute in chennai with placement
Thank you for sharing such great information with us. I really appreciate everything that you’ve done here and am glad to know that you really care about the world that we live in.
ReplyDeletePHP course
PHP Training
Best PHP training in chennai
PHP Training Center in Chennai
PHP Institutes in Chennai
Nice idea,keep sharing your ideas with us.i hope this information's will be helpful for the new learners.
ReplyDeleteCloud computing Training Bangalore
Cloud Computing Training in Nolambur
Cloud Computing Training in Saidapet
Cloud Computing Training in Perungudi
Thank you for sharing this useful information. I got more information in this blogs comment. Your site was awesome. keep update on some more tutorials…..
ReplyDeleteBig Data Hadoop Training in velachery
Big Data Hadoop Training in Tambaram
Big Data Training in Tambaram
Big Data Hadoop Training in velachery
Big Data Hadoop Training in kandanchavadi
Big Data Hadoop Training in sholinganallur
Nice post. By reading your blog, i get inspired and this provides some useful information. Thank you for posting.
ReplyDeletePhotoshop Training Classes in Chennai
Best Photoshop Training in Chennai
Photoshop Course Training in Chennai
Photoshop Course
Photoshop Classes
Photoshop Training
Photoshop Classes for Photographers
I liked your blog.Thanks for your interest in sharing your ideas.keep doing more.
ReplyDeleteSpoken English Classes in Chennai Anna Nagar
Spoken English Classes in Mogappair West
Spoken English Classes in Chennai Ayanavaram
Best Spoken English Institute in Anna Nagar
Spoken English Classes in Chennai Purasawalkam
Spoken English Class in Anna Nagar
Spoken English Classes near me
Informative blog and it was up to the point describing the information very effectively. Keep updating more post like this.
ReplyDeleteOracle Apps DBA Training in Chennai | Oracle DBA Training Institutes in Chennai | Oracle DBA Training | Oracle DBA Course in Adyar | Oracle DBA Course in Tambaram | Oracle DBA Course in Velachery
Thanks for sharing this information admin, it helps me to learn new things. Continue sharing more like this.
ReplyDeleteBest CCNA Training Institute in Chennai
ccna certification in Chennai
ccna Training in Velachery
RPA Training
Blue Prism Training Chennai
UiPath Training
Thanks for sharing such a information. It shows your in-depth knowledge. Pls keep updating.
ReplyDeleteHadoop Admin Training in Chennai
Hadoop Administration Training in Chennai
Hadoop Administration Course in Chennai
Hadoop Administration Training
Big Data Administrator Training
Hadoop Administration Course
Hadoop Admin Training Institutes in Chennai
Amazing Post. I am very much impressed with your choice of words. The content showcases your in-depth knowledge in this subject. Thanks for sharing.
ReplyDeleteSocial Media Certification
Social Media Classes
Social Media Marketing Certification
Social Media Marketing Classes
Social Media Marketing Training Courses
Social Marketing Training
Social Media Online Training
Extra-ordinary. The way you narrate the post makes it a exemplorary piece of work. Pls Keep writing.
ReplyDeleteTableau Training in Chennai
Tableau Course in Chennai
Tableau Certification in Chennai
Tableau Training Institutes in Chennai
Tableau Certification
Tableau Training
Tableau Course
Very useful education blog
ReplyDeleteThanks for sharing
Tableau training in chennai
Thanks for sharing such a information. It shows your in-depth knowledge.I am very much impressed with your choice of words.
ReplyDeleteUI Path Online Training
UI Path Training in Hyderabad
good post for users
ReplyDeleteFull Stack Training in Chennai | Certification | Online Training Course | Full Stack Training in Bangalore | Certification | Online Training Course | Full Stack Training in Hyderabad | Certification | Online Training Course | Full Stack Training in Pune | Certification | Online Training Course | Full Stack Training | Certification | Full Stack Online Training Course
HI thanku so much this infromation this is greatful blog
ReplyDeletecs executive
freecseetvideolectures/
Read More About The Latest XM REVIEW Review In This Article. Learn How The Broker Operates And If You Should Avoid Trading With It Or Not.
ReplyDelete
ReplyDeleteThis piece of article is amazing. I would also like the world to know about a company which gives best quality logistics service ,ie is AFM Logistics Pvt Ltd is an international freight forwarding and customs clearing company established in Delhi. The company was constituted in 2012 and is indulged in providing complete logistics solution. The company has its own setup and wide network of agents throughout the world. International Logistics Companies In India . They are the best air cargo and ocean freight forwarding company in Delhi, India. AFM Logistics Pvt Ltd has been working as Import and Export Agent in India since 2012. They have been providing personal baggage shipping services in India for a very long time.