forked from SeleniumHQ/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwd.html
484 lines (350 loc) · 18.4 KB
/
wd.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
<!doctype html>
<meta charset=utf-8>
<title>WebDriver</title>
<link rel=stylesheet href=se.css>
<link rel=prev href=start.html title="Getting Started">
<link rel=next href=remote.html title="Remote WebDriver">
<script src=docs.js></script>
<h1>WebDriver</h1>
<p>The biggest change in Selenium recently
has been the inclusion of the WebDriver API.
Driving a browser natively as a user would either locally
or on a remote machine using the Selenium server
it marks a leap forward in terms of browser automation.
<p>Selenium WebDriver fits in the same role as RC did,
and has incorporated the original 1.x bindings.
It refers to both the language bindings
and the implementations of the individual browser controlling code.
This is commonly referred to as just <em>WebDriver</em>
or sometimes as <em>Selenium 2</em>.
<p>Selenium 1.0 + WebDriver = Selenium 2.0
<ul>
<li>WebDriver is designed in a simpler
and more concise programming interface
along with addressing some limitations in the Selenium-RC API.
<li>WebDriver is a compact object-oriented API
when compared to Selenium 1.0.
<li>It drives the browser much more effectively
and overcomes the limitations of Selenium 1
that affected our functional test coverage,
like the file upload or download, pop-ups, and dialogs barrier.
<li>WebDriver overcomes the limitation of Selenium RC's
<a href="https://en.wikipedia.org/wiki/Same-origin_policy">single-host origin policy.</a>
</ul>
<h2>Driver Requirements</h2>
<p>Through WebDriver, Selenium supports all major browsers on the market
such as Chrom(ium), Firefox, Internet Explorer, Opera, and Safari.
Where possible WebDriver drives the browser
using the browser's built-in support for automation,
although not all browsers have official support for remote control.
<p>WebDriver's aim is to emulate a real user's interaction
with the browser as closely as possible.
This is possible at varying levels in different browsers.
For more detalis on the different driver idiosyncracies,
please see <em><a href=drivers.html>Driver Idiosyncracies</a></em>.
<p>Even though all the drivers share a single user-facing interface
for contolling the browser,
they have slightly different ways of setting up browser sessions.
Since many of the driver implementations are provided by third parties,
they are not included in the standard Selenium distribution.
<p>Driver instantiation, profile management, and various browser specific settings
are examples of parameters that have different requirements depending on the browser.
This section explains the basic requirements
for getting you started with the different browsers.
<h3>Chromium/Chrome</h3>
<p>To drive Chrome or Chromium, you have to download
<a href=//code.google.com/p/chromedriver/downloads/list>chromedriver</a>
and put it in a folder that is on your system's path.
<p>On Linux or Mac OS this means modifying
the <var>PATH</var> environmental variable.
You can see what directories, separated by a colon,
that makes up your system's path by executing the following command:
<pre><code>% echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin</code></pre>
<p>To include chromedriver on the path if it isn't already,
make sure you include the chromedriver binary's parent directory.
The following line will set the <var>PATH</var> environmental variable
its current content, plus an additional path added after the colon:
<pre><code>% export PATH="$PATH:/path/to/chromedriver"</code></pre>
<p>When chromedriver is available on your path,
you should be able to execute the _chromedriver_ executable from any directory.
<p>To instantiate a Chrome/Chromium session, you can do the following:
<pre><code class=java>WebDriver driver = new ChromeDriver();</code></pre>
<p>Remember that you have to set the path to the chromedriver executable.
This is possible using the following line:
<pre><code class=java>System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");</code></pre>
<pre><code class=ruby>require "selenium-webdriver"
driver = Selenium::WebDriver.for :chrome</code></pre>
<p>The chromedriver is implemented as a WebDriver remote server
that by exposing Chrome's internal automation proxy interface
instructs the browser what to do.
<h3>Firefox</h3>
<p>The driver for Firefox is maintained by the Selenium project
and works by installing a browser add-on
in Firefox' profile before starting the browser.
The WebDriver client then communicates with that add-on
to instruct the browser what to do.
<p>The approach for instantiating a WebDriver session to Firefox
is pretty much the same as for Chrome and Chromium,
but doesn't require any additional dependencies:
<pre><code class=java>WebDriver driver = new FirefoxDriver();</code></pre>
<pre><code class=rb>require "selenium-webdriver"
driver = Selenium::WebDriver.for :firefox</code></pre>
<h3>Internet Explorer</h3>
<h3>Opera (Presto-based)</h3>
<p>Setting up support for Opera is fairly similar to the Chrome approach
in that they are both supported by third parties.
Consequently you need to set up a dependency to
the <code>com.opera:operadriver</code> artifact (if using Maven)
or <a href=//code.google.com/p/selenium/downloads/list>download a prebuilt standalone server JAR</a>
As long as the JAR is available on your classpath, you should be good to go.
<p>If you use Python or Ruby as your language of choice
you must set the <var>SELENIUM_SERVER_JAR</var> environmental variable
to point to the location of the binary JAR.
<p>On Linux and Mac OS X you can do it for your current shell session
by doing this:
<pre><code>% export SELENIUM_SERVER_JAR=/path/to/operadriver.jar</code></pre>
<p>It's possible to set this in your shell's profile (e.g. <em>~/.bashrc</em>)
to have the variable set every time you launch a new shell session.
Alternatively you can set the variable programmatically in your test runner.
In Python you'd do something along the lines of
<pre><code class=py>import os
os.environ["SELENIUM_SERVER_JAR"] = "/path/to/selenium-server-standalone.jar"</code></pre>
<p>The equivalent in Ruby:
<pre><code class=rb>ENV["SELENIUM_SERVER_JAR"] = "/path/to/selenium-server-standalone.jar"</code></pre>
<p>Instantiating a driver session is similar to Firefox and Chromium:
<pre><code class=java>WebDriver driver = new OperaDriver();</code></pre>
<pre><code class=rb>require "selenium-webdriver"
driver = Selenium::WebDriver.for :opera</code></pre>
<h3>Safari</h3>
<h3>Specialized Browsers</h3>
<h4> HtmlUnit</h4>
<h4>PhantomJS</h4>
<h2>Browser Launching and Manipulation</h2>
<!-- #codeExamples -->
<!-- Remember to cover profile and extensions here -->
<h3>Ruby</h3>
<p>Ruby is not installed by default on Windows. Download the latest [version](http://rubyinstaller.org/downloads) and run the installer. You can leave all settings at default values, except at the *Installation Destination and Optional Tasks* screen check *Add Ruby executables to your PATH* checkbox. To drive any browser you have to install selenium-webdriver Ruby gem. To install it, open command prompt and type this:
<pre><code>gem install selenium-webdriver</code></pre>
<h3>Internet Explorer</h3>
<p>Internet Explorer is installed by default on Windows, so no installation is needed. To drive Internet Explorer on Windows you have to download the latest [Internet Explorer Driver](https://code.google.com/p/selenium/downloads/list) and put the file into a folder that is in PATH. To find out which directories are in PATH type `echo %PATH%` in command prompt.
<pre><code>echo %PATH%
C:\Ruby200\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem</code></pre>
`C:\Ruby200\bin` looks like a good place. Unzip `IEDriverServer` file and move `IEDriverServer.exe` there.
This should open a new Internet Explorer window:
<pre><code class=rb>require "selenium-webdriver"
driver = Selenium::WebDriver.for :internet_explorer</code></pre>
<h2>Waits</h2>
<p>WebDriver can generally be said to have a blocking API.
Because it is an out-of-process library that
<em>instructs</em> the browser what to do,
and because the web platform has an intrinsicly asynchronous nature,
WebDriver doesn't track the active, real-time state of the DOM.
This comes with some challenges that we will discuss here.
<p>From experience,
most intermittents that arise from use of Selenium and WebDriver
are connected to <em>race conditions</em> that occur between
the browser and the user's instructions.
An example could be that the user instructs the browser to navigate to a page,
then gets a <strong>no such element</strong> error
when trying to find an element.
<p>Consider the following document:
<pre class=html><code><!doctype html>
<meta charset=utf-8>
<title>Race Condition Example<title>
<script>
var initialised = false;
window.addEventListener("load", function() {
var newElement = document.createElement("p");
newElement.textContent = "Hello from JavaScript!";
document.body.appendChild(newElement);
initialised = true;
});
</script></code></pre>
<p>The WebDriver instructions might look innocent enough:
<pre class=py><code>driver.navigate("file:///race_condition.html")
el = driver.find_element_by_tag_name("p")
assert el.text == "Hello from JavaScript!"</code></pre>
<p>The issue here is that the default
<a href=#page_load_strategy>page load strategy</a>
used in WebDriver listens for the <var>document.readyState</var>
to change to <code>"complete"</code> before returning from the call to <em>navigate</em>.
Because the <code>p</code> element is
added <em>after</em> the document has completed loading,
this WebDriver script <em>might</em> be intermittent.
It “might” be intermittent because no guarantees can be made
about elements or events that trigger asynchronously
without explicitly waiting—or blocking—on those events.
<p>Fortunately, using the normal instruction set available on
the <em><a href=#webelement>WebElement</a></em> interface—such
as <em>WebElement.click</em> and <em>WebElement.sendKeys</em>—are
guaranteed to be synchronous,
in that the function calls won't return
(or the callback won't trigger in callback-style languages)
until the the command has been completed in the browser.
The advanced user interaction APIs,
<em><a href=#keyboard>Keyboard</a></em> and
<em><a href=#mouse>Mouse</a></em>,
are exceptions as they are explicitly intended as
“do what I say” asynchronous commands.
<p>Waiting is having the automated task execution
elapse a certain amount of time before continuing with the next step.
<p>To overcome the problem of race conditions
between the browser and your WebDriver script,
most Selenium clients ships with a <em>wait</em> package.
When employing a wait,
you are using what is commonly referred to
as an <em><a href=#explicit_wait>explicit wait</a></em>.
<h3>Explicit Wait</h3>
<p><em>Explicit waits</em> are available to Selenium clients
for imperative, procedural languages.
They allow your code to halt program execution,
or freezing the thread,
until the <em>condition</em> you pass it resolves.
The condition is called with a certain frequency
until the timeout of the wait is elapsed.
This means that for as long as the condition returns a falsy value,
it will keep trying and keep waiting.
<p>Since explicit waits allow you to wait for a condition to occur,
they make a good fit for synchronising the state between the browser and its DOM,
and your WebDriver script.
<p>To remedy our buggy instruction set from earlier,
we could employ a wait to have the <em>findElement</em> call
wait until the dynamically added element from the script
has been added to the DOM:
<pre class=py><code>from selenium.webdriver.support.ui import WebDriverWait
def document_initialised(driver):
return driver.execute_script("return initialised")
driver.navigate("file:///race_condition.html")
WebDriverWait(driver).until(document_initialised)
el = driver.find_element_by_tag_name("p")
assert el.text == "Hello from JavaScript!"</code></pre>
<p>We pass in the <em>condition</em> as a function reference
that the <em>wait</em> will run repeatedly until its return value is truthy.
A “truthful” return value is anything that evaluates to boolean true
in the language at hand, such as a string, number, a boolean,
an object (including a <em>WebElement</em>),
or a populated (non-empty) sequence or list.
That means an <em>empty list</em> evaluates to false.
When the condition is truthful and the blocking wait is aborted,
the return value from the condition becomes the return value of the wait.
<p>With this knowledge,
and because the wait utility ignores <em>no such element</em> errors by default,
we can refactor our instructions to be more concise:
<pre class=py><code>from selenium.webdriver.support.ui import WebDriverWait
driver.navigate("file:///race_condition.html")
el = WebDriverWait(driver).until(lambda d: return d.find_element_by_tag_name("p"))
assert el.text == "Hello from JavaScript!"</code></pre>
<p>In that example we pass in an anonymous function
(but we could also define it explicitly as we did earlier so it may be reused).
The first and only argument that is passed to our condition
is always a reference to our driver object, <em>WebDriver</em>
(called <em>d</em> in the example).
In a multi-threaded environment you should be careful
to operate on the driver reference passed in to the condition
rather than the reference to the driver in the outer scope.
<p>Because the wait will swallow <em>no such element</em> errors
that are raised when the element isn't found,
the condition will retry until the element is found.
Then it will take the return value, a <em>WebElement</em>,
an pass it back through to our script.
<p>If the condition fails,
e.g. a truthful return value from the condition is never reached,
the wait will throw/raise an error/exception called a <em>timeout error</em>.
<h4>Options</h4>
<p>The wait condition can be customised to match your needs.
Sometimes it's unnecessary to wait the full extent of the default timeout,
as the penalty for not hitting a successful condition can be expensive.
<p>The wait lets you pass in an argument to override the timeout:
<pre class=py><code>WebDriverWait(driver, timeout=3).until(some_condition)</code></pre>
<h4>Expected Conditions</h4>
<p>Because it's quite a common occurence
to have to synchronise the DOM and your instructions,
most clients also come with a set of predefined <em>expected conditions</em>.
As might be obvious by the name,
they are conditions that are predefined for frequent wait operations.
<p>The conditions available in the different language bindings vary,
but this is a non-exhaustive list of a few:
<!-- TODO(ato): Fill in -->
<dl>
<dt>alert is present
<dd>
<dt>element exists
<dd>
<dt>element is visible
<dd>
<dt>title contains
<dd>
<dt>title is
<dd>
<dt>element staleness
<dd>
<dt>visible text
<dd>
</dl>
<p>You can refer to the API documentation for each client binding
to find an exhaustive list of expected conditions:
<ul>
<li>Java's <code><a href=//selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html>org.openqa.selenium.support.ui.ExpectedConditions</a></code> package
<li>Python's <code><a href=//selenium.googlecode.com/git/docs/api/py/webdriver_support/selenium.webdriver.support.expected_conditions.html>selenium.webdriver.support.expected_conditions</a></code> package
<li>.NET's <code><a href=//selenium.googlecode.com/git/docs/api/dotnet/html/AllMembers_T_OpenQA_Selenium_Support_UI_ExpectedConditions.htm>OpenQA.Selenium.Support.UI.ExpectedConditions</a></code> type
</ul>
<h3>Implicit Waiting</h3>
<p>There is a second type of wait that is distinct from
<a href=#explicit_wait>explicit waits</a> called <em>implicit waiting</em>.
By implicitly waiting, WebDriver to poll the DOM
for a certain duration when trying to find <em>any</em> element.
This can be useful when certain elements on the webpage
will not be available immediately and needs some time to load.
<p>Implicit waiting for elements to appear is disabled by default
and will need to be manually enabled on a per-session basis.
Mixing <a href=#explicit_wait>explicit waits</a> and implicit waiting
will cause unintended consequences,
namely waits sleeping for the maximum time
even if the element is available or condition is true.
<p><strong>Warning:</strong>
Do not mix implicit and explicit waits.
Doing so can cause unpredictable wait times.
For example setting an implicit wait of 10 seconds
and an explicit wait of 15 seconds,
could cause a timeout to occur after 20 seconds.
<p>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, meaning disabled.
Once set, the implicit wait is set for the life of the session.
<pre class=java><code>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"));</code></pre>
<h4>FluentWait</h4>
<p>FluentWait instance defines the maximum amount of time to wait for a condition,
as well as the frequency with which to check the condition.
<p>User may configure the wait to ignore specific types of exceptions whilst waiting,
such as NoSuchElementExceptions when searching for an element on the page.
<pre><code class=java>// Waiting 30 seconds for an element to be present on the page, checking
// for its presence once every 5 seconds.
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(30, SECONDS)
.pollingEvery(5, SECONDS)
.ignoring(NoSuchElementException.class);
WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(By.id("foo"));
}
});</code></pre>
<pre><code class=java>FluentWait<By> fluentWait = new FluentWait<By>(By.tagName("TEXTAREA"));
fluentWait.pollingEvery(100, TimeUnit.MILLISECONDS);
fluentWait.withTimeout(1000, TimeUnit.MILLISECONDS);
fluentWait.until(new Predicate<By>() {
public boolean apply(By by) {
try {
return browser.findElement(by).isDisplayed();
} catch (NoSuchElementException ex) {
return false;
}
}
});
browser.findElement(By.tagName("TEXTAREA")).sendKeys("text to enter");</code></pre>
<h2 class=support_classes>Support Classes</h2>
<h2 class=http_proxies>HTTP Proxies</h2>