2
* Copyright 2004 ThoughtWorks, Inc
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
18
// TODO: stop navigating this.browserbot.document() ... it breaks encapsulation
20
var storedVars = new Object();
22
function Selenium(browserbot) {
24
* Defines an object that runs Selenium commands.
26
* <h3><a name="locators"></a>Element Locators</h3>
28
* Element Locators tell Selenium which HTML element a command refers to.
29
* The format of a locator is:</p>
31
* <em>locatorType</em><strong>=</strong><em>argument</em>
35
* We support the following strategies for locating elements:
39
* <li><strong>identifier</strong>=<em>id</em>:
40
* Select the element with the specified @id attribute. If no match is
41
* found, select the first element whose @name attribute is <em>id</em>.
42
* (This is normally the default; see below.)</li>
43
* <li><strong>id</strong>=<em>id</em>:
44
* Select the element with the specified @id attribute.</li>
46
* <li><strong>name</strong>=<em>name</em>:
47
* Select the first element with the specified @name attribute.
48
* <ul class="first last simple">
50
* <li>name=username</li>
53
* <p>The name may optionally be followed by one or more <em>element-filters</em>, separated from the name by whitespace. If the <em>filterType</em> is not specified, <strong>value</strong> is assumed.</p>
55
* <ul class="first last simple">
56
* <li>name=flavour value=chocolate</li>
59
* <li><strong>dom</strong>=<em>javascriptExpression</em>:
61
* Find an element by evaluating the specified string. This allows you to traverse the HTML Document Object
62
* Model using JavaScript. Note that you must not return a value in this string; simply make it the last expression in the block.
63
* <ul class="first last simple">
64
* <li>dom=document.forms['myForm'].myDropdown</li>
65
* <li>dom=document.images[56]</li>
66
* <li>dom=function foo() { return document.links[1]; }; foo();</li>
71
* <li><strong>xpath</strong>=<em>xpathExpression</em>:
72
* Locate an element using an XPath expression.
73
* <ul class="first last simple">
74
* <li>xpath=//img[@alt='The image alt text']</li>
75
* <li>xpath=//table[@id='table1']//tr[4]/td[2]</li>
76
* <li>xpath=//a[contains(@href,'#id1')]</li>
77
* <li>xpath=//a[contains(@href,'#id1')]/@class</li>
78
* <li>xpath=(//table[@class='stylee'])//th[text()='theHeaderText']/../td</li>
79
* <li>xpath=//input[@name='name2' and @value='yes']</li>
80
* <li>xpath=//*[text()="right"]</li>
84
* <li><strong>link</strong>=<em>textPattern</em>:
85
* Select the link (anchor) element which contains text matching the
86
* specified <em>pattern</em>.
87
* <ul class="first last simple">
88
* <li>link=The link text</li>
93
* <li><strong>css</strong>=<em>cssSelectorSyntax</em>:
94
* Select the element using css selectors. Please refer to <a href="http://www.w3.org/TR/REC-CSS2/selector.html">CSS2 selectors</a>, <a href="http://www.w3.org/TR/2001/CR-css3-selectors-20011113/">CSS3 selectors</a> for more information. You can also check the TestCssLocators test in the selenium test suite for an example of usage, which is included in the downloaded selenium core package.
95
* <ul class="first last simple">
96
* <li>css=a[href="#id3"]</li>
97
* <li>css=span#firstChild + span</li>
99
* <p>Currently the css selector locator supports all css1, css2 and css3 selectors except namespace in css3, some pseudo classes(:nth-of-type, :nth-last-of-type, :first-of-type, :last-of-type, :only-of-type, :visited, :hover, :active, :focus, :indeterminate) and pseudo elements(::first-line, ::first-letter, ::selection, ::before, ::after). </p>
102
* <li><strong>ui</strong>=<em>uiSpecifierString</em>:
103
* Locate an element by resolving the UI specifier string to another locator, and evaluating it. See the <a href="http://svn.openqa.org/fisheye/browse/~raw,r=trunk/selenium/trunk/src/main/resources/core/scripts/ui-doc.html">Selenium UI-Element Reference</a> for more details.
104
* <ul class="first last simple">
105
* <li>ui=loginPages::loginButton()</li>
106
* <li>ui=settingsPages::toggle(label=Hide Email)</li>
107
* <li>ui=forumPages::postBody(index=2)//a[2]</li>
114
* Without an explicit locator prefix, Selenium uses the following default
118
* <ul class="simple">
119
* <li><strong>dom</strong>, for locators starting with "document."</li>
120
* <li><strong>xpath</strong>, for locators starting with "//"</li>
121
* <li><strong>identifier</strong>, otherwise</li>
124
* <h3><a name="element-filters">Element Filters</a></h3>
126
* <p>Element filters can be used with a locator to refine a list of candidate elements. They are currently used only in the 'name' element-locator.</p>
127
* <p>Filters look much like locators, ie.</p>
129
* <em>filterType</em><strong>=</strong><em>argument</em></blockquote>
131
* <p>Supported element-filters are:</p>
132
* <p><strong>value=</strong><em>valuePattern</em></p>
134
* Matches elements based on their values. This is particularly useful for refining a list of similarly-named toggle-buttons.</blockquote>
135
* <p><strong>index=</strong><em>index</em></p>
137
* Selects a single element based on its position in the list (offset from zero).</blockquote>
140
* <h3><a name="patterns"></a>String-match Patterns</h3>
143
* Various Pattern syntaxes are available for matching string values:
146
* <li><strong>glob:</strong><em>pattern</em>:
147
* Match a string against a "glob" (aka "wildmat") pattern. "Glob" is a
148
* kind of limited regular-expression syntax typically used in command-line
149
* shells. In a glob pattern, "*" represents any sequence of characters, and "?"
150
* represents any single character. Glob patterns match against the entire
152
* <li><strong>regexp:</strong><em>regexp</em>:
153
* Match a string using a regular-expression. The full power of JavaScript
154
* regular-expressions is available.</li>
155
* <li><strong>regexpi:</strong><em>regexpi</em>:
156
* Match a string using a case-insensitive regular-expression.</li>
157
* <li><strong>exact:</strong><em>string</em>:
159
* Match a string exactly, verbatim, without any of that fancy wildcard
163
* If no pattern prefix is specified, Selenium assumes that it's a "glob"
167
* For commands that return multiple values (such as verifySelectOptions),
168
* the string being matched is a comma-separated list of the return values,
169
* where both commas and backslashes in the values are backslash-escaped.
170
* When providing a pattern, the optional matching syntax (i.e. glob,
171
* regexp, etc.) is specified once, as usual, at the beginning of the
175
this.browserbot = browserbot;
176
this.optionLocatorFactory = new OptionLocatorFactory();
177
// DGF for backwards compatibility
178
this.page = function() {
181
this.defaultTimeout = Selenium.DEFAULT_TIMEOUT;
182
this.mouseSpeed = Selenium.DEFAULT_MOUSE_SPEED;
185
Selenium.DEFAULT_TIMEOUT = 30 * 1000;
186
Selenium.DEFAULT_MOUSE_SPEED = 10;
187
Selenium.RIGHT_MOUSE_CLICK = 2;
189
Selenium.decorateFunctionWithTimeout = function(f, timeout) {
194
var timeoutTime = getTimeoutTime(timeout);
197
if (new Date().getTime() > timeoutTime) {
198
throw new SeleniumError("Timed out after " + timeout + "ms");
204
Selenium.createForWindow = function(window, proxyInjectionMode) {
205
if (!window.location) {
206
throw "error: not a window!";
208
return new Selenium(BrowserBot.createForWindow(window, proxyInjectionMode));
211
Selenium.prototype.reset = function() {
212
this.defaultTimeout = Selenium.DEFAULT_TIMEOUT;
213
// todo: this.browserbot.reset()
214
this.browserbot.selectWindow("null");
215
this.browserbot.resetPopups();
218
Selenium.prototype.doClick = function(locator) {
220
* Clicks on a link, button, checkbox or radio button. If the click action
221
* causes a new page to load (like a link usually does), call
224
* @param locator an element locator
227
var element = this.browserbot.findElement(locator);
228
var elementWithHref = getAncestorOrSelfWithJavascriptHref(element);
230
if (browserVersion.isChrome && elementWithHref != null) {
231
// SEL-621: Firefox chrome: Race condition bug in alert-handling code
233
// This appears to be because javascript href's are being executed in a
234
// separate thread from the main thread when running in chrome mode.
236
// This workaround injects a callback into the executing href that
237
// lowers a flag, which is initially raised. Execution of this click
238
// command will wait for the flag to be lowered.
240
var win = elementWithHref.ownerDocument.defaultView;
241
var originalLocation = win.location.href;
242
var originalHref = elementWithHref.href;
244
elementWithHref.href = 'javascript:try { '
245
+ originalHref.replace(/^\s*javascript:/i, "")
246
+ ' } finally { window._executingJavascriptHref = undefined; }' ;
248
win._executingJavascriptHref = true;
250
this.browserbot.clickElement(element);
252
return Selenium.decorateFunctionWithTimeout(function() {
256
if (win.location.href != originalLocation) {
257
// navigated to some other page ... javascript from previous
258
// page can't still be executing!
261
if (! win._executingJavascriptHref) {
263
elementWithHref.href = originalHref;
266
// maybe the javascript removed the element ... should be
267
// no danger in not reverting its href attribute
273
}, this.defaultTimeout);
276
this.browserbot.clickElement(element);
279
Selenium.prototype.doDoubleClick = function(locator) {
281
* Double clicks on a link, button, checkbox or radio button. If the double click action
282
* causes a new page to load (like a link usually does), call
285
* @param locator an element locator
288
var element = this.browserbot.findElement(locator);
289
this.browserbot.doubleClickElement(element);
292
Selenium.prototype.doContextMenu = function(locator) {
294
* Simulates opening the context menu for the specified element (as might happen if the user "right-clicked" on the element).
296
* @param locator an element locator
299
var element = this.browserbot.findElement(locator);
300
this.browserbot.contextMenuOnElement(element);
303
Selenium.prototype.doClickAt = function(locator, coordString) {
305
* Clicks on a link, button, checkbox or radio button. If the click action
306
* causes a new page to load (like a link usually does), call
309
* @param locator an element locator
310
* @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
311
* event relative to the element returned by the locator.
314
var element = this.browserbot.findElement(locator);
315
var clientXY = getClientXY(element, coordString)
316
this.doMouseMove(locator);
317
this.doMouseDown(locator);
318
this.browserbot.clickElement(element, clientXY[0], clientXY[1]);
319
this.doMouseUp(locator);
322
Selenium.prototype.doDoubleClickAt = function(locator, coordString) {
324
* Doubleclicks on a link, button, checkbox or radio button. If the action
325
* causes a new page to load (like a link usually does), call
328
* @param locator an element locator
329
* @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
330
* event relative to the element returned by the locator.
333
var element = this.browserbot.findElement(locator);
334
var clientXY = getClientXY(element, coordString)
335
this.doMouseMove(locator);
336
this.doMouseDown(locator);
337
this.browserbot.doubleClickElement(element, clientXY[0], clientXY[1]);
338
this.doMouseUp(locator);
341
Selenium.prototype.doContextMenuAt = function(locator, coordString) {
343
* Simulates opening the context menu for the specified element (as might happen if the user "right-clicked" on the element).
345
* @param locator an element locator
346
* @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
347
* event relative to the element returned by the locator.
350
var element = this.browserbot.findElement(locator);
351
var clientXY = getClientXY(element, coordString)
352
this.browserbot.contextMenuOnElement(element, clientXY[0], clientXY[1]);
355
Selenium.prototype.doFireEvent = function(locator, eventName) {
357
* Explicitly simulate an event, to trigger the corresponding "on<em>event</em>"
360
* @param locator an <a href="#locators">element locator</a>
361
* @param eventName the event name, e.g. "focus" or "blur"
363
var element = this.browserbot.findElement(locator);
364
triggerEvent(element, eventName, false);
367
Selenium.prototype.doFocus = function(locator) {
368
/** Move the focus to the specified element; for example, if the element is an input field, move the cursor to that field.
370
* @param locator an <a href="#locators">element locator</a>
372
var element = this.browserbot.findElement(locator);
376
triggerEvent(element, "focus", false);
380
Selenium.prototype.doKeyPress = function(locator, keySequence) {
382
* Simulates a user pressing and releasing a key.
384
* @param locator an <a href="#locators">element locator</a>
385
* @param keySequence Either be a string("\" followed by the numeric keycode
386
* of the key to be pressed, normally the ASCII value of that key), or a single
387
* character. For example: "w", "\119".
389
var element = this.browserbot.findElement(locator);
390
triggerKeyEvent(element, 'keypress', keySequence, true,
391
this.browserbot.controlKeyDown,
392
this.browserbot.altKeyDown,
393
this.browserbot.shiftKeyDown,
394
this.browserbot.metaKeyDown);
397
Selenium.prototype.doShiftKeyDown = function() {
399
* Press the shift key and hold it down until doShiftUp() is called or a new page is loaded.
402
this.browserbot.shiftKeyDown = true;
405
Selenium.prototype.doShiftKeyUp = function() {
407
* Release the shift key.
410
this.browserbot.shiftKeyDown = false;
413
Selenium.prototype.doMetaKeyDown = function() {
415
* Press the meta key and hold it down until doMetaUp() is called or a new page is loaded.
418
this.browserbot.metaKeyDown = true;
421
Selenium.prototype.doMetaKeyUp = function() {
423
* Release the meta key.
426
this.browserbot.metaKeyDown = false;
429
Selenium.prototype.doAltKeyDown = function() {
431
* Press the alt key and hold it down until doAltUp() is called or a new page is loaded.
434
this.browserbot.altKeyDown = true;
437
Selenium.prototype.doAltKeyUp = function() {
439
* Release the alt key.
442
this.browserbot.altKeyDown = false;
445
Selenium.prototype.doControlKeyDown = function() {
447
* Press the control key and hold it down until doControlUp() is called or a new page is loaded.
450
this.browserbot.controlKeyDown = true;
453
Selenium.prototype.doControlKeyUp = function() {
455
* Release the control key.
458
this.browserbot.controlKeyDown = false;
461
Selenium.prototype.doKeyDown = function(locator, keySequence) {
463
* Simulates a user pressing a key (without releasing it yet).
465
* @param locator an <a href="#locators">element locator</a>
466
* @param keySequence Either be a string("\" followed by the numeric keycode
467
* of the key to be pressed, normally the ASCII value of that key), or a single
468
* character. For example: "w", "\119".
470
var element = this.browserbot.findElement(locator);
471
triggerKeyEvent(element, 'keydown', keySequence, true,
472
this.browserbot.controlKeyDown,
473
this.browserbot.altKeyDown,
474
this.browserbot.shiftKeyDown,
475
this.browserbot.metaKeyDown);
478
Selenium.prototype.doKeyUp = function(locator, keySequence) {
480
* Simulates a user releasing a key.
482
* @param locator an <a href="#locators">element locator</a>
483
* @param keySequence Either be a string("\" followed by the numeric keycode
484
* of the key to be pressed, normally the ASCII value of that key), or a single
485
* character. For example: "w", "\119".
487
var element = this.browserbot.findElement(locator);
488
triggerKeyEvent(element, 'keyup', keySequence, true,
489
this.browserbot.controlKeyDown,
490
this.browserbot.altKeyDown,
491
this.browserbot.shiftKeyDown,
492
this.browserbot.metaKeyDown);
495
function getClientXY(element, coordString) {
501
coords = coordString.split(/,/);
502
x = Number(coords[0]);
503
y = Number(coords[1]);
509
// Get position of element,
510
// Return 2 item array with clientX and clientY
511
return [Selenium.prototype.getElementPositionLeft(element) + x, Selenium.prototype.getElementPositionTop(element) + y];
514
Selenium.prototype.doMouseOver = function(locator) {
516
* Simulates a user hovering a mouse over the specified element.
518
* @param locator an <a href="#locators">element locator</a>
520
var element = this.browserbot.findElement(locator);
521
this.browserbot.triggerMouseEvent(element, 'mouseover', true);
524
Selenium.prototype.doMouseOut = function(locator) {
526
* Simulates a user moving the mouse pointer away from the specified element.
528
* @param locator an <a href="#locators">element locator</a>
530
var element = this.browserbot.findElement(locator);
531
this.browserbot.triggerMouseEvent(element, 'mouseout', true);
534
Selenium.prototype.doMouseDown = function(locator) {
536
* Simulates a user pressing the left mouse button (without releasing it yet) on
537
* the specified element.
539
* @param locator an <a href="#locators">element locator</a>
541
var element = this.browserbot.findElement(locator);
542
this.browserbot.triggerMouseEvent(element, 'mousedown', true);
545
Selenium.prototype.doMouseDownRight = function(locator) {
547
* Simulates a user pressing the right mouse button (without releasing it yet) on
548
* the specified element.
550
* @param locator an <a href="#locators">element locator</a>
552
var element = this.browserbot.findElement(locator);
553
this.browserbot.triggerMouseEvent(element, 'mousedown', true, undefined, undefined, Selenium.RIGHT_MOUSE_CLICK);
556
Selenium.prototype.doMouseDownAt = function(locator, coordString) {
558
* Simulates a user pressing the left mouse button (without releasing it yet) at
559
* the specified location.
561
* @param locator an <a href="#locators">element locator</a>
562
* @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
563
* event relative to the element returned by the locator.
565
var element = this.browserbot.findElement(locator);
566
var clientXY = getClientXY(element, coordString)
568
this.browserbot.triggerMouseEvent(element, 'mousedown', true, clientXY[0], clientXY[1]);
571
Selenium.prototype.doMouseDownRightAt = function(locator, coordString) {
573
* Simulates a user pressing the right mouse button (without releasing it yet) at
574
* the specified location.
576
* @param locator an <a href="#locators">element locator</a>
577
* @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
578
* event relative to the element returned by the locator.
580
var element = this.browserbot.findElement(locator);
581
var clientXY = getClientXY(element, coordString)
583
this.browserbot.triggerMouseEvent(element, 'mousedown', true, clientXY[0], clientXY[1], Selenium.RIGHT_MOUSE_CLICK);
586
Selenium.prototype.doMouseUp = function(locator) {
588
* Simulates the event that occurs when the user releases the mouse button (i.e., stops
589
* holding the button down) on the specified element.
591
* @param locator an <a href="#locators">element locator</a>
593
var element = this.browserbot.findElement(locator);
594
this.browserbot.triggerMouseEvent(element, 'mouseup', true);
597
Selenium.prototype.doMouseUpRight = function(locator) {
599
* Simulates the event that occurs when the user releases the right mouse button (i.e., stops
600
* holding the button down) on the specified element.
602
* @param locator an <a href="#locators">element locator</a>
604
var element = this.browserbot.findElement(locator);
605
this.browserbot.triggerMouseEvent(element, 'mouseup', true, undefined, undefined, Selenium.RIGHT_MOUSE_CLICK);
608
Selenium.prototype.doMouseUpAt = function(locator, coordString) {
610
* Simulates the event that occurs when the user releases the mouse button (i.e., stops
611
* holding the button down) at the specified location.
613
* @param locator an <a href="#locators">element locator</a>
614
* @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
615
* event relative to the element returned by the locator.
617
var element = this.browserbot.findElement(locator);
618
var clientXY = getClientXY(element, coordString)
620
this.browserbot.triggerMouseEvent(element, 'mouseup', true, clientXY[0], clientXY[1]);
623
Selenium.prototype.doMouseUpRightAt = function(locator, coordString) {
625
* Simulates the event that occurs when the user releases the right mouse button (i.e., stops
626
* holding the button down) at the specified location.
628
* @param locator an <a href="#locators">element locator</a>
629
* @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
630
* event relative to the element returned by the locator.
632
var element = this.browserbot.findElement(locator);
633
var clientXY = getClientXY(element, coordString)
635
this.browserbot.triggerMouseEvent(element, 'mouseup', true, clientXY[0], clientXY[1], Selenium.RIGHT_MOUSE_CLICK);
638
Selenium.prototype.doMouseMove = function(locator) {
640
* Simulates a user pressing the mouse button (without releasing it yet) on
641
* the specified element.
643
* @param locator an <a href="#locators">element locator</a>
645
var element = this.browserbot.findElement(locator);
646
this.browserbot.triggerMouseEvent(element, 'mousemove', true);
649
Selenium.prototype.doMouseMoveAt = function(locator, coordString) {
651
* Simulates a user pressing the mouse button (without releasing it yet) on
652
* the specified element.
654
* @param locator an <a href="#locators">element locator</a>
655
* @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
656
* event relative to the element returned by the locator.
659
var element = this.browserbot.findElement(locator);
660
var clientXY = getClientXY(element, coordString)
662
this.browserbot.triggerMouseEvent(element, 'mousemove', true, clientXY[0], clientXY[1]);
665
Selenium.prototype.doType = function(locator, value) {
667
* Sets the value of an input field, as though you typed it in.
669
* <p>Can also be used to set the value of combo boxes, check boxes, etc. In these cases,
670
* value should be the value of the option selected, not the visible text.</p>
672
* @param locator an <a href="#locators">element locator</a>
673
* @param value the value to type
675
if (this.browserbot.controlKeyDown || this.browserbot.altKeyDown || this.browserbot.metaKeyDown) {
676
throw new SeleniumError("type not supported immediately after call to controlKeyDown() or altKeyDown() or metaKeyDown()");
678
// TODO fail if it can't be typed into.
679
var element = this.browserbot.findElement(locator);
680
if (this.browserbot.shiftKeyDown) {
681
value = new String(value).toUpperCase();
683
this.browserbot.replaceText(element, value);
686
Selenium.prototype.doTypeKeys = function(locator, value) {
688
* Simulates keystroke events on the specified element, as though you typed the value key-by-key.
690
* <p>This is a convenience method for calling keyDown, keyUp, keyPress for every character in the specified string;
691
* this is useful for dynamic UI widgets (like auto-completing combo boxes) that require explicit key events.</p>
693
* <p>Unlike the simple "type" command, which forces the specified value into the page directly, this command
694
* may or may not have any visible effect, even in cases where typing keys would normally have a visible effect.
695
* For example, if you use "typeKeys" on a form element, you may or may not see the results of what you typed in
697
* <p>In some cases, you may need to use the simple "type" command to set the value of the field and then the "typeKeys" command to
698
* send the keystroke events corresponding to what you just typed.</p>
700
* @param locator an <a href="#locators">element locator</a>
701
* @param value the value to type
703
var keys = new String(value).split("");
704
for (var i = 0; i < keys.length; i++) {
706
this.doKeyDown(locator, c);
707
this.doKeyUp(locator, c);
708
this.doKeyPress(locator, c);
712
Selenium.prototype.doSetSpeed = function(value) {
714
* Set execution speed (i.e., set the millisecond length of a delay which will follow each selenium operation). By default, there is no such delay, i.e.,
715
* the delay is 0 milliseconds.
717
* @param value the number of milliseconds to pause after operation
719
throw new SeleniumError("this operation is only implemented in selenium-rc, and should never result in a request making it across the wire");
722
Selenium.prototype.getSpeed = function() {
724
* Get execution speed (i.e., get the millisecond length of the delay following each selenium operation). By default, there is no such delay, i.e.,
725
* the delay is 0 milliseconds.
729
* @return string the execution speed in milliseconds.
731
throw new SeleniumError("this operation is only implemented in selenium-rc, and should never result in a request making it across the wire");
734
Selenium.prototype.findToggleButton = function(locator) {
735
var element = this.browserbot.findElement(locator);
736
if (element.checked == null) {
737
Assert.fail("Element " + locator + " is not a toggle-button.");
742
Selenium.prototype.doCheck = function(locator) {
744
* Check a toggle-button (checkbox/radio)
746
* @param locator an <a href="#locators">element locator</a>
748
this.findToggleButton(locator).checked = true;
751
Selenium.prototype.doUncheck = function(locator) {
753
* Uncheck a toggle-button (checkbox/radio)
755
* @param locator an <a href="#locators">element locator</a>
757
this.findToggleButton(locator).checked = false;
760
Selenium.prototype.doSelect = function(selectLocator, optionLocator) {
762
* Select an option from a drop-down using an option locator.
765
* Option locators provide different ways of specifying options of an HTML
766
* Select element (e.g. for selecting a specific option, or for asserting
767
* that the selected option satisfies a specification). There are several
768
* forms of Select Option Locator.
771
* <li><strong>label</strong>=<em>labelPattern</em>:
772
* matches options based on their labels, i.e. the visible text. (This
774
* <ul class="first last simple">
775
* <li>label=regexp:^[Oo]ther</li>
778
* <li><strong>value</strong>=<em>valuePattern</em>:
779
* matches options based on their values.
780
* <ul class="first last simple">
781
* <li>value=other</li>
786
* <li><strong>id</strong>=<em>id</em>:
788
* matches options based on their ids.
789
* <ul class="first last simple">
790
* <li>id=option1</li>
793
* <li><strong>index</strong>=<em>index</em>:
794
* matches an option based on its index (offset from zero).
795
* <ul class="first last simple">
802
* If no option locator prefix is provided, the default behaviour is to match on <strong>label</strong>.
806
* @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
807
* @param optionLocator an option locator (a label by default)
809
var element = this.browserbot.findElement(selectLocator);
810
if (!("options" in element)) {
811
throw new SeleniumError("Specified element is not a Select (has no options)");
813
var locator = this.optionLocatorFactory.fromLocatorString(optionLocator);
814
var option = locator.findOption(element);
815
this.browserbot.selectOption(element, option);
820
Selenium.prototype.doAddSelection = function(locator, optionLocator) {
822
* Add a selection to the set of selected options in a multi-select element using an option locator.
824
* @see #doSelect for details of option locators
826
* @param locator an <a href="#locators">element locator</a> identifying a multi-select box
827
* @param optionLocator an option locator (a label by default)
829
var element = this.browserbot.findElement(locator);
830
if (!("options" in element)) {
831
throw new SeleniumError("Specified element is not a Select (has no options)");
833
var locator = this.optionLocatorFactory.fromLocatorString(optionLocator);
834
var option = locator.findOption(element);
835
this.browserbot.addSelection(element, option);
838
Selenium.prototype.doRemoveSelection = function(locator, optionLocator) {
840
* Remove a selection from the set of selected options in a multi-select element using an option locator.
842
* @see #doSelect for details of option locators
844
* @param locator an <a href="#locators">element locator</a> identifying a multi-select box
845
* @param optionLocator an option locator (a label by default)
848
var element = this.browserbot.findElement(locator);
849
if (!("options" in element)) {
850
throw new SeleniumError("Specified element is not a Select (has no options)");
852
var locator = this.optionLocatorFactory.fromLocatorString(optionLocator);
853
var option = locator.findOption(element);
854
this.browserbot.removeSelection(element, option);
857
Selenium.prototype.doRemoveAllSelections = function(locator) {
859
* Unselects all of the selected options in a multi-select element.
861
* @param locator an <a href="#locators">element locator</a> identifying a multi-select box
863
var element = this.browserbot.findElement(locator);
864
if (!("options" in element)) {
865
throw new SeleniumError("Specified element is not a Select (has no options)");
867
for (var i = 0; i < element.options.length; i++) {
868
this.browserbot.removeSelection(element, element.options[i]);
872
Selenium.prototype.doSubmit = function(formLocator) {
874
* Submit the specified form. This is particularly useful for forms without
875
* submit buttons, e.g. single-input "Search" forms.
877
* @param formLocator an <a href="#locators">element locator</a> for the form you want to submit
879
var form = this.browserbot.findElement(formLocator);
880
return this.browserbot.submit(form);
884
Selenium.prototype.makePageLoadCondition = function(timeout) {
885
if (timeout == null) {
886
timeout = this.defaultTimeout;
888
// if the timeout is zero, we won't wait for the page to load before returning
892
return Selenium.decorateFunctionWithTimeout(fnBind(this._isNewPageLoaded, this), timeout);
895
Selenium.prototype.doOpen = function(url) {
897
* Opens an URL in the test frame. This accepts both relative and absolute
900
* The "open" command waits for the page to load before proceeding,
901
* ie. the "AndWait" suffix is implicit.
903
* <em>Note</em>: The URL must be on the same domain as the runner HTML
904
* due to security restrictions in the browser (Same Origin Policy). If you
905
* need to open an URL on another domain, use the Selenium Server to start a
906
* new browser session on that domain.
908
* @param url the URL to open; may be relative or absolute
910
this.browserbot.openLocation(url);
911
if (window["proxyInjectionMode"] == null || !window["proxyInjectionMode"]) {
912
return this.makePageLoadCondition();
913
} // in PI mode, just return "OK"; the server will waitForLoad
916
Selenium.prototype.doOpenWindow = function(url, windowID) {
918
* Opens a popup window (if a window with that ID isn't already open).
919
* After opening the window, you'll need to select it using the selectWindow
922
* <p>This command can also be a useful workaround for bug SEL-339. In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the "onLoad" event, for example).
923
* In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using
924
* an empty (blank) url, like this: openWindow("", "myFunnyWindow").</p>
926
* @param url the URL to open, which can be blank
927
* @param windowID the JavaScript window ID of the window to select
929
this.browserbot.openWindow(url, windowID);
932
Selenium.prototype.doSelectWindow = function(windowID) {
934
* Selects a popup window using a window locator; once a popup window has been selected, all
935
* commands go to that window. To select the main window again, use null
940
* Window locators provide different ways of specifying the window object:
941
* by title, by internal JavaScript "name," or by JavaScript variable.
944
* <li><strong>title</strong>=<em>My Special Window</em>:
945
* Finds the window using the text that appears in the title bar. Be careful;
946
* two windows can share the same title. If that happens, this locator will
949
* <li><strong>name</strong>=<em>myWindow</em>:
950
* Finds the window using its internal JavaScript "name" property. This is the second
951
* parameter "windowName" passed to the JavaScript method window.open(url, windowName, windowFeatures, replaceFlag)
952
* (which Selenium intercepts).
954
* <li><strong>var</strong>=<em>variableName</em>:
955
* Some pop-up windows are unnamed (anonymous), but are associated with a JavaScript variable name in the current
956
* application window, e.g. "window.foo = window.open(url);". In those cases, you can open the window using
961
* If no window locator prefix is provided, we'll try to guess what you mean like this:</p>
962
* <p>1.) if windowID is null, (or the string "null") then it is assumed the user is referring to the original window instantiated by the browser).</p>
963
* <p>2.) if the value of the "windowID" parameter is a JavaScript variable name in the current application window, then it is assumed
964
* that this variable contains the return value from a call to the JavaScript window.open() method.</p>
965
* <p>3.) Otherwise, selenium looks in a hash it maintains that maps string names to window "names".</p>
966
* <p>4.) If <em>that</em> fails, we'll try looping over all of the known windows to try to find the appropriate "title".
967
* Since "title" is not necessarily unique, this may have unexpected behavior.</p>
969
* <p>If you're having trouble figuring out the name of a window that you want to manipulate, look at the Selenium log messages
970
* which identify the names of windows created via window.open (and therefore intercepted by Selenium). You will see messages
971
* like the following for each window as it is opened:</p>
973
* <p><code>debug: window.open call intercepted; window ID (which you can use with selectWindow()) is "myNewWindow"</code></p>
975
* <p>In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the "onLoad" event, for example).
976
* (This is bug SEL-339.) In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using
977
* an empty (blank) url, like this: openWindow("", "myFunnyWindow").</p>
979
* @param windowID the JavaScript window ID of the window to select
981
this.browserbot.selectWindow(windowID);
984
Selenium.prototype.doSelectPopUp = function(windowID) {
986
* Simplifies the process of selecting a popup window (and does not offer
987
* functionality beyond what <code>selectWindow()</code> already provides).
989
* <li>If <code>windowID</code> is either not specified, or specified as
990
* "null", the first non-top window is selected. The top window is the one
991
* that would be selected by <code>selectWindow()</code> without providing a
992
* <code>windowID</code> . This should not be used when more than one popup
993
* window is in play.</li>
994
* <li>Otherwise, the window will be looked up considering
995
* <code>windowID</code> as the following in order: 1) the "name" of the
996
* window, as specified to <code>window.open()</code>; 2) a javascript
997
* variable which is a reference to a window; and 3) the title of the
998
* window. This is the same ordered lookup performed by
999
* <code>selectWindow</code> .</li>
1002
* @param windowID an identifier for the popup window, which can take on a
1003
* number of different meanings
1005
this.browserbot.selectPopUp(windowID);
1008
Selenium.prototype.doDeselectPopUp = function() {
1010
* Selects the main window. Functionally equivalent to using
1011
* <code>selectWindow()</code> and specifying no value for
1012
* <code>windowID</code>.
1014
this.browserbot.selectWindow();
1017
Selenium.prototype.doSelectFrame = function(locator) {
1019
* Selects a frame within the current window. (You may invoke this command
1020
* multiple times to select nested frames.) To select the parent frame, use
1021
* "relative=parent" as a locator; to select the top frame, use "relative=top".
1022
* You can also select a frame by its 0-based index number; select the first frame with
1023
* "index=0", or the third frame with "index=2".
1025
* <p>You may also use a DOM expression to identify the frame you want directly,
1026
* like this: <code>dom=frames["main"].frames["subframe"]</code></p>
1028
* @param locator an <a href="#locators">element locator</a> identifying a frame or iframe
1030
this.browserbot.selectFrame(locator);
1033
Selenium.prototype.getWhetherThisFrameMatchFrameExpression = function(currentFrameString, target) {
1035
* Determine whether current/locator identify the frame containing this running code.
1037
* <p>This is useful in proxy injection mode, where this code runs in every
1038
* browser frame and window, and sometimes the selenium server needs to identify
1039
* the "current" frame. In this case, when the test calls selectFrame, this
1040
* routine is called for each frame to figure out which one has been selected.
1041
* The selected frame will return true, while all others will return false.</p>
1043
* @param currentFrameString starting frame
1044
* @param target new frame (which might be relative to the current one)
1045
* @return boolean true if the new frame is this code's window
1047
return this.browserbot.doesThisFrameMatchFrameExpression(currentFrameString, target);
1050
Selenium.prototype.getWhetherThisWindowMatchWindowExpression = function(currentWindowString, target) {
1052
* Determine whether currentWindowString plus target identify the window containing this running code.
1054
* <p>This is useful in proxy injection mode, where this code runs in every
1055
* browser frame and window, and sometimes the selenium server needs to identify
1056
* the "current" window. In this case, when the test calls selectWindow, this
1057
* routine is called for each window to figure out which one has been selected.
1058
* The selected window will return true, while all others will return false.</p>
1060
* @param currentWindowString starting window
1061
* @param target new window (which might be relative to the current one, e.g., "_parent")
1062
* @return boolean true if the new window is this code's window
1064
if (window.opener!=null && window.opener[target]!=null && window.opener[target]==window) {
1070
Selenium.prototype.doWaitForPopUp = function(windowID, timeout) {
1072
* Waits for a popup window to appear and load up.
1074
* @param windowID the JavaScript window "name" of the window that will appear (not the text of the title bar)
1075
* If unspecified, or specified as "null", this command will
1076
* wait for the first non-top window to appear (don't rely
1077
* on this if you are working with multiple popups
1079
* @param timeout a timeout in milliseconds, after which the action will return with an error.
1080
* If this value is not specified, the default Selenium
1081
* timeout will be used. See the setTimeout() command.
1084
var timeout = this.defaultTimeout;
1086
var timeoutTime = getTimeoutTime(timeout);
1088
var popupLoadedPredicate = function () {
1091
if (windowID && windowID != 'null') {
1092
targetWindow = selenium.browserbot.getWindowByName(windowID, true);
1095
var names = selenium.browserbot.getNonTopWindowNames();
1096
targetWindow = selenium.browserbot.getWindowByName(names[0], true);
1100
if (new Date().getTime() > timeoutTime) {
1105
if (!targetWindow) return false;
1106
if (!targetWindow.location) return false;
1107
if ("about:blank" == targetWindow.location) return false;
1108
if (browserVersion.isKonqueror) {
1109
if ("/" == targetWindow.location.href) {
1110
// apparently Konqueror uses this as the temporary location, instead of about:blank
1114
if (browserVersion.isSafari) {
1115
if(targetWindow.location.href == selenium.browserbot.buttonWindow.location.href) {
1116
// Apparently Safari uses this as the temporary location, instead of about:blank
1118
LOG.debug("DGF what a world!");
1122
if (!targetWindow.document) return false;
1123
if (!selenium.browserbot.getCurrentWindow().document.readyState) {
1124
// This is Firefox, with no readyState extension
1127
if ('complete' != targetWindow.document.readyState) return false;
1131
return Selenium.decorateFunctionWithTimeout(popupLoadedPredicate, timeout);
1134
Selenium.prototype.doWaitForPopUp.dontCheckAlertsAndConfirms = true;
1136
Selenium.prototype.doChooseCancelOnNextConfirmation = function() {
1139
* By default, Selenium's overridden window.confirm() function will
1140
* return true, as if the user had manually clicked OK; after running
1141
* this command, the next call to confirm() will return false, as if
1142
* the user had clicked Cancel. Selenium will then resume using the
1143
* default behavior for future confirmations, automatically returning
1144
* true (OK) unless/until you explicitly call this command for each
1148
* Take note - every time a confirmation comes up, you must
1149
* consume it with a corresponding getConfirmation, or else
1150
* the next selenium operation will fail.
1153
this.browserbot.cancelNextConfirmation(false);
1156
Selenium.prototype.doChooseOkOnNextConfirmation = function() {
1159
* Undo the effect of calling chooseCancelOnNextConfirmation. Note
1160
* that Selenium's overridden window.confirm() function will normally automatically
1161
* return true, as if the user had manually clicked OK, so you shouldn't
1162
* need to use this command unless for some reason you need to change
1163
* your mind prior to the next confirmation. After any confirmation, Selenium will resume using the
1164
* default behavior for future confirmations, automatically returning
1165
* true (OK) unless/until you explicitly call chooseCancelOnNextConfirmation for each
1169
* Take note - every time a confirmation comes up, you must
1170
* consume it with a corresponding getConfirmation, or else
1171
* the next selenium operation will fail.
1175
this.browserbot.cancelNextConfirmation(true);
1178
Selenium.prototype.doAnswerOnNextPrompt = function(answer) {
1180
* Instructs Selenium to return the specified answer string in response to
1181
* the next JavaScript prompt [window.prompt()].
1184
* @param answer the answer to give in response to the prompt pop-up
1186
this.browserbot.setNextPromptResult(answer);
1189
Selenium.prototype.doGoBack = function() {
1191
* Simulates the user clicking the "back" button on their browser.
1194
this.browserbot.goBack();
1197
Selenium.prototype.doRefresh = function() {
1199
* Simulates the user clicking the "Refresh" button on their browser.
1202
this.browserbot.refresh();
1205
Selenium.prototype.doClose = function() {
1207
* Simulates the user clicking the "close" button in the titlebar of a popup
1210
this.browserbot.close();
1213
Selenium.prototype.ensureNoUnhandledPopups = function() {
1214
if (this.browserbot.hasAlerts()) {
1215
throw new SeleniumError("There was an unexpected Alert! [" + this.browserbot.getNextAlert() + "]");
1217
if ( this.browserbot.hasConfirmations() ) {
1218
throw new SeleniumError("There was an unexpected Confirmation! [" + this.browserbot.getNextConfirmation() + "]");
1222
Selenium.prototype.isAlertPresent = function() {
1224
* Has an alert occurred?
1227
* This function never throws an exception
1229
* @return boolean true if there is an alert
1231
return this.browserbot.hasAlerts();
1234
Selenium.prototype.isPromptPresent = function() {
1236
* Has a prompt occurred?
1239
* This function never throws an exception
1241
* @return boolean true if there is a pending prompt
1243
return this.browserbot.hasPrompts();
1246
Selenium.prototype.isConfirmationPresent = function() {
1248
* Has confirm() been called?
1251
* This function never throws an exception
1253
* @return boolean true if there is a pending confirmation
1255
return this.browserbot.hasConfirmations();
1257
Selenium.prototype.getAlert = function() {
1259
* Retrieves the message of a JavaScript alert generated during the previous action, or fail if there were no alerts.
1261
* <p>Getting an alert has the same effect as manually clicking OK. If an
1262
* alert is generated but you do not consume it with getAlert, the next Selenium action
1265
* <p>Under Selenium, JavaScript alerts will NOT pop up a visible alert
1268
* <p>Selenium does NOT support JavaScript alerts that are generated in a
1269
* page's onload() event handler. In this case a visible dialog WILL be
1270
* generated and Selenium will hang until someone manually clicks OK.</p>
1271
* @return string The message of the most recent JavaScript alert
1274
if (!this.browserbot.hasAlerts()) {
1275
Assert.fail("There were no alerts");
1277
return this.browserbot.getNextAlert();
1279
Selenium.prototype.getAlert.dontCheckAlertsAndConfirms = true;
1281
Selenium.prototype.getConfirmation = function() {
1283
* Retrieves the message of a JavaScript confirmation dialog generated during
1284
* the previous action.
1287
* By default, the confirm function will return true, having the same effect
1288
* as manually clicking OK. This can be changed by prior execution of the
1289
* chooseCancelOnNextConfirmation command.
1292
* If an confirmation is generated but you do not consume it with getConfirmation,
1293
* the next Selenium action will fail.
1297
* NOTE: under Selenium, JavaScript confirmations will NOT pop up a visible
1302
* NOTE: Selenium does NOT support JavaScript confirmations that are
1303
* generated in a page's onload() event handler. In this case a visible
1304
* dialog WILL be generated and Selenium will hang until you manually click
1308
* @return string the message of the most recent JavaScript confirmation dialog
1310
if (!this.browserbot.hasConfirmations()) {
1311
Assert.fail("There were no confirmations");
1313
return this.browserbot.getNextConfirmation();
1315
Selenium.prototype.getConfirmation.dontCheckAlertsAndConfirms = true;
1317
Selenium.prototype.getPrompt = function() {
1319
* Retrieves the message of a JavaScript question prompt dialog generated during
1320
* the previous action.
1322
* <p>Successful handling of the prompt requires prior execution of the
1323
* answerOnNextPrompt command. If a prompt is generated but you
1324
* do not get/verify it, the next Selenium action will fail.</p>
1326
* <p>NOTE: under Selenium, JavaScript prompts will NOT pop up a visible
1329
* <p>NOTE: Selenium does NOT support JavaScript prompts that are generated in a
1330
* page's onload() event handler. In this case a visible dialog WILL be
1331
* generated and Selenium will hang until someone manually clicks OK.</p>
1332
* @return string the message of the most recent JavaScript question prompt
1334
if (! this.browserbot.hasPrompts()) {
1335
Assert.fail("There were no prompts");
1337
return this.browserbot.getNextPrompt();
1340
Selenium.prototype.getLocation = function() {
1341
/** Gets the absolute URL of the current page.
1343
* @return string the absolute URL of the current page
1345
return this.browserbot.getCurrentWindow().location.href;
1348
Selenium.prototype.getTitle = function() {
1349
/** Gets the title of the current page.
1351
* @return string the title of the current page
1353
return this.browserbot.getTitle();
1357
Selenium.prototype.getBodyText = function() {
1359
* Gets the entire text of the page.
1360
* @return string the entire text of the page
1362
return this.browserbot.bodyText();
1366
Selenium.prototype.getValue = function(locator) {
1368
* Gets the (whitespace-trimmed) value of an input field (or anything else with a value parameter).
1369
* For checkbox/radio elements, the value will be "on" or "off" depending on
1370
* whether the element is checked or not.
1372
* @param locator an <a href="#locators">element locator</a>
1373
* @return string the element value, or "on/off" for checkbox/radio elements
1375
var element = this.browserbot.findElement(locator)
1376
return getInputValue(element).trim();
1379
Selenium.prototype.getText = function(locator) {
1381
* Gets the text of an element. This works for any element that contains
1382
* text. This command uses either the textContent (Mozilla-like browsers) or
1383
* the innerText (IE-like browsers) of the element, which is the rendered
1384
* text shown to the user.
1386
* @param locator an <a href="#locators">element locator</a>
1387
* @return string the text of the element
1389
var element = this.browserbot.findElement(locator);
1390
return getText(element).trim();
1393
Selenium.prototype.doHighlight = function(locator) {
1395
* Briefly changes the backgroundColor of the specified element yellow. Useful for debugging.
1397
* @param locator an <a href="#locators">element locator</a>
1399
var element = this.browserbot.findElement(locator);
1400
this.browserbot.highlight(element, true);
1403
Selenium.prototype.getEval = function(script) {
1404
/** Gets the result of evaluating the specified JavaScript snippet. The snippet may
1405
* have multiple lines, but only the result of the last line will be returned.
1407
* <p>Note that, by default, the snippet will run in the context of the "selenium"
1408
* object itself, so <code>this</code> will refer to the Selenium object. Use <code>window</code> to
1409
* refer to the window of your application, e.g. <code>window.document.getElementById('foo')</code></p>
1411
* <p>If you need to use
1412
* a locator to refer to a single element in your application page, you can
1413
* use <code>this.browserbot.findElement("id=foo")</code> where "id=foo" is your locator.</p>
1415
* @param script the JavaScript snippet to run
1416
* @return string the results of evaluating the snippet
1419
var window = this.browserbot.getCurrentWindow();
1420
var result = eval(script);
1421
// Selenium RC doesn't allow returning null
1422
if (null == result) return "null";
1425
throw new SeleniumError("Threw an exception: " + extractExceptionMessage(e));
1429
Selenium.prototype.isChecked = function(locator) {
1431
* Gets whether a toggle-button (checkbox/radio) is checked. Fails if the specified element doesn't exist or isn't a toggle-button.
1432
* @param locator an <a href="#locators">element locator</a> pointing to a checkbox or radio button
1433
* @return boolean true if the checkbox is checked, false otherwise
1435
var element = this.browserbot.findElement(locator);
1436
if (element.checked == null) {
1437
throw new SeleniumError("Element " + locator + " is not a toggle-button.");
1439
return element.checked;
1442
Selenium.prototype.getTable = function(tableCellAddress) {
1444
* Gets the text from a cell of a table. The cellAddress syntax
1445
* tableLocator.row.column, where row and column start at 0.
1447
* @param tableCellAddress a cell address, e.g. "foo.1.4"
1448
* @return string the text from the specified cell
1450
// This regular expression matches "tableName.row.column"
1451
// For example, "mytable.3.4"
1452
pattern = /(.*)\.(\d+)\.(\d+)/;
1454
if(!pattern.test(tableCellAddress)) {
1455
throw new SeleniumError("Invalid target format. Correct format is tableName.rowNum.columnNum");
1458
pieces = tableCellAddress.match(pattern);
1460
tableName = pieces[1];
1464
var table = this.browserbot.findElement(tableName);
1465
if (row > table.rows.length) {
1466
Assert.fail("Cannot access row " + row + " - table has " + table.rows.length + " rows");
1468
else if (col > table.rows[row].cells.length) {
1469
Assert.fail("Cannot access column " + col + " - table row has " + table.rows[row].cells.length + " columns");
1472
actualContent = getText(table.rows[row].cells[col]);
1473
return actualContent.trim();
1478
Selenium.prototype.getSelectedLabels = function(selectLocator) {
1479
/** Gets all option labels (visible text) for selected options in the specified select or multi-select element.
1481
* @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
1482
* @return string[] an array of all selected option labels in the specified select drop-down
1484
return this.findSelectedOptionProperties(selectLocator, "text");
1487
Selenium.prototype.getSelectedLabel = function(selectLocator) {
1488
/** Gets option label (visible text) for selected option in the specified select element.
1490
* @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
1491
* @return string the selected option label in the specified select drop-down
1493
return this.findSelectedOptionProperty(selectLocator, "text");
1496
Selenium.prototype.getSelectedValues = function(selectLocator) {
1497
/** Gets all option values (value attributes) for selected options in the specified select or multi-select element.
1499
* @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
1500
* @return string[] an array of all selected option values in the specified select drop-down
1502
return this.findSelectedOptionProperties(selectLocator, "value");
1505
Selenium.prototype.getSelectedValue = function(selectLocator) {
1506
/** Gets option value (value attribute) for selected option in the specified select element.
1508
* @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
1509
* @return string the selected option value in the specified select drop-down
1511
return this.findSelectedOptionProperty(selectLocator, "value");
1514
Selenium.prototype.getSelectedIndexes = function(selectLocator) {
1515
/** Gets all option indexes (option number, starting at 0) for selected options in the specified select or multi-select element.
1517
* @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
1518
* @return string[] an array of all selected option indexes in the specified select drop-down
1520
return this.findSelectedOptionProperties(selectLocator, "index");
1523
Selenium.prototype.getSelectedIndex = function(selectLocator) {
1524
/** Gets option index (option number, starting at 0) for selected option in the specified select element.
1526
* @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
1527
* @return string the selected option index in the specified select drop-down
1529
return this.findSelectedOptionProperty(selectLocator, "index");
1532
Selenium.prototype.getSelectedIds = function(selectLocator) {
1533
/** Gets all option element IDs for selected options in the specified select or multi-select element.
1535
* @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
1536
* @return string[] an array of all selected option IDs in the specified select drop-down
1538
return this.findSelectedOptionProperties(selectLocator, "id");
1541
Selenium.prototype.getSelectedId = function(selectLocator) {
1542
/** Gets option element ID for selected option in the specified select element.
1544
* @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
1545
* @return string the selected option ID in the specified select drop-down
1547
return this.findSelectedOptionProperty(selectLocator, "id");
1550
Selenium.prototype.isSomethingSelected = function(selectLocator) {
1551
/** Determines whether some option in a drop-down menu is selected.
1553
* @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
1554
* @return boolean true if some option has been selected, false otherwise
1556
var element = this.browserbot.findElement(selectLocator);
1557
if (!("options" in element)) {
1558
throw new SeleniumError("Specified element is not a Select (has no options)");
1561
var selectedOptions = [];
1563
for (var i = 0; i < element.options.length; i++) {
1564
if (element.options[i].selected)
1572
Selenium.prototype.findSelectedOptionProperties = function(locator, property) {
1573
var element = this.browserbot.findElement(locator);
1574
if (!("options" in element)) {
1575
throw new SeleniumError("Specified element is not a Select (has no options)");
1578
var selectedOptions = [];
1580
for (var i = 0; i < element.options.length; i++) {
1581
if (element.options[i].selected)
1583
var propVal = element.options[i][property];
1584
selectedOptions.push(propVal);
1587
if (selectedOptions.length == 0) Assert.fail("No option selected");
1588
return selectedOptions;
1591
Selenium.prototype.findSelectedOptionProperty = function(locator, property) {
1592
var selectedOptions = this.findSelectedOptionProperties(locator, property);
1593
if (selectedOptions.length > 1) {
1594
Assert.fail("More than one selected option!");
1596
return selectedOptions[0];
1599
Selenium.prototype.getSelectOptions = function(selectLocator) {
1600
/** Gets all option labels in the specified select drop-down.
1602
* @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
1603
* @return string[] an array of all option labels in the specified select drop-down
1605
var element = this.browserbot.findElement(selectLocator);
1607
var selectOptions = [];
1609
for (var i = 0; i < element.options.length; i++) {
1610
var option = element.options[i].text;
1611
selectOptions.push(option);
1614
return selectOptions;
1618
Selenium.prototype.getAttribute = function(attributeLocator) {
1620
* Gets the value of an element attribute. The value of the attribute may
1621
* differ across browsers (this is the case for the "style" attribute, for
1624
* @param attributeLocator an element locator followed by an @ sign and then the name of the attribute, e.g. "foo@bar"
1625
* @return string the value of the specified attribute
1627
var result = this.browserbot.findAttribute(attributeLocator);
1628
if (result == null) {
1629
throw new SeleniumError("Could not find element attribute: " + attributeLocator);
1634
Selenium.prototype.isTextPresent = function(pattern) {
1636
* Verifies that the specified text pattern appears somewhere on the rendered page shown to the user.
1637
* @param pattern a <a href="#patterns">pattern</a> to match with the text of the page
1638
* @return boolean true if the pattern matches the text, false otherwise
1640
var allText = this.browserbot.bodyText();
1642
var patternMatcher = new PatternMatcher(pattern);
1643
if (patternMatcher.strategy == PatternMatcher.strategies.glob) {
1644
if (pattern.indexOf("glob:")==0) {
1645
pattern = pattern.substring("glob:".length); // strip off "glob:"
1647
patternMatcher.matcher = new PatternMatcher.strategies.globContains(pattern);
1649
else if (patternMatcher.strategy == PatternMatcher.strategies.exact) {
1650
pattern = pattern.substring("exact:".length); // strip off "exact:"
1651
return allText.indexOf(pattern) != -1;
1653
return patternMatcher.matches(allText);
1656
Selenium.prototype.isElementPresent = function(locator) {
1658
* Verifies that the specified element is somewhere on the page.
1659
* @param locator an <a href="#locators">element locator</a>
1660
* @return boolean true if the element is present, false otherwise
1662
var element = this.browserbot.findElementOrNull(locator);
1663
if (element == null) {
1669
Selenium.prototype.isVisible = function(locator) {
1671
* Determines if the specified element is visible. An
1672
* element can be rendered invisible by setting the CSS "visibility"
1673
* property to "hidden", or the "display" property to "none", either for the
1674
* element itself or one if its ancestors. This method will fail if
1675
* the element is not present.
1677
* @param locator an <a href="#locators">element locator</a>
1678
* @return boolean true if the specified element is visible, false otherwise
1681
element = this.browserbot.findElement(locator);
1682
// DGF if it's an input tag of type "hidden" then it's not visible
1683
if (element.tagName) {
1684
var tagName = new String(element.tagName).toLowerCase();
1685
if (tagName == "input") {
1687
var elementType = new String(element.type).toLowerCase();
1688
if (elementType == "hidden") {
1694
var visibility = this.findEffectiveStyleProperty(element, "visibility");
1695
var _isDisplayed = this._isDisplayed(element);
1696
return (visibility != "hidden" && _isDisplayed);
1699
Selenium.prototype.findEffectiveStyleProperty = function(element, property) {
1700
var effectiveStyle = this.findEffectiveStyle(element);
1701
var propertyValue = effectiveStyle[property];
1702
if (propertyValue == 'inherit' && element.parentNode.style) {
1703
return this.findEffectiveStyleProperty(element.parentNode, property);
1705
return propertyValue;
1708
Selenium.prototype._isDisplayed = function(element) {
1709
var display = this.findEffectiveStyleProperty(element, "display");
1710
if (display == "none") return false;
1711
if (element.parentNode.style) {
1712
return this._isDisplayed(element.parentNode);
1717
Selenium.prototype.findEffectiveStyle = function(element) {
1718
if (element.style == undefined) {
1719
return undefined; // not a styled element
1721
var window = this.browserbot.getCurrentWindow();
1722
if (window.getComputedStyle) {
1724
return window.getComputedStyle(element, null);
1726
if (element.currentStyle) {
1727
// non-standard IE alternative
1728
return element.currentStyle;
1729
// TODO: this won't really work in a general sense, as
1730
// currentStyle is not identical to getComputedStyle()
1731
// ... but it's good enough for "visibility"
1734
if (window.document.defaultView && window.document.defaultView.getComputedStyle) {
1735
return window.document.defaultView.getComputedStyle(element, null);
1739
throw new SeleniumError("cannot determine effective stylesheet in this browser");
1742
Selenium.prototype.isEditable = function(locator) {
1744
* Determines whether the specified input element is editable, ie hasn't been disabled.
1745
* This method will fail if the specified element isn't an input element.
1747
* @param locator an <a href="#locators">element locator</a>
1748
* @return boolean true if the input element is editable, false otherwise
1750
var element = this.browserbot.findElement(locator);
1751
if (element.value == undefined) {
1752
Assert.fail("Element " + locator + " is not an input.");
1754
if (element.disabled) {
1757
// DGF "readonly" is a bit goofy... it doesn't necessarily have a value
1758
// You can write <input readonly value="black">
1759
var readOnlyNode = element.getAttributeNode('readonly');
1761
// DGF on IE, every input element has a readOnly node, but it may be false
1762
if (typeof(readOnlyNode.nodeValue) == "boolean") {
1763
var readOnly = readOnlyNode.nodeValue;
1774
Selenium.prototype.getAllButtons = function() {
1775
/** Returns the IDs of all buttons on the page.
1777
* <p>If a given button has no ID, it will appear as "" in this array.</p>
1779
* @return string[] the IDs of all buttons on the page
1781
return this.browserbot.getAllButtons();
1784
Selenium.prototype.getAllLinks = function() {
1785
/** Returns the IDs of all links on the page.
1787
* <p>If a given link has no ID, it will appear as "" in this array.</p>
1789
* @return string[] the IDs of all links on the page
1791
return this.browserbot.getAllLinks();
1794
Selenium.prototype.getAllFields = function() {
1795
/** Returns the IDs of all input fields on the page.
1797
* <p>If a given field has no ID, it will appear as "" in this array.</p>
1799
* @return string[] the IDs of all field on the page
1801
return this.browserbot.getAllFields();
1804
Selenium.prototype.getAttributeFromAllWindows = function(attributeName) {
1805
/** Returns an array of JavaScript property values from all known windows having one.
1807
* @param attributeName name of an attribute on the windows
1808
* @return string[] the set of values of this attribute from all known windows.
1810
var attributes = new Array();
1812
var win = selenium.browserbot.topWindow;
1814
// DGF normally you should use []s instead of eval "win."+attributeName
1815
// but in this case, attributeName may contain dots (e.g. document.title)
1816
// in that case, we have no choice but to use eval...
1817
attributes.push(eval("win."+attributeName));
1818
for (var windowName in this.browserbot.openedWindows)
1821
win = selenium.browserbot.openedWindows[windowName];
1822
attributes.push(eval("win."+attributeName));
1823
} catch (e) {} // DGF If we miss one... meh. It's probably closed or inaccessible anyway.
1828
Selenium.prototype.findWindow = function(soughtAfterWindowPropertyValue) {
1829
var targetPropertyName = "name";
1830
if (soughtAfterWindowPropertyValue.match("^title=")) {
1831
targetPropertyName = "document.title";
1832
soughtAfterWindowPropertyValue = soughtAfterWindowPropertyValue.replace(/^title=/, "");
1836
// If we are not in proxy injection mode, then the top-level test window will be named selenium_myiframe.
1837
// But as far as the interface goes, we are expected to match a blank string to this window, if
1838
// we are searching with respect to the widow name.
1839
// So make a special case so that this logic will work:
1840
if (PatternMatcher.matches(soughtAfterWindowPropertyValue, "")) {
1841
return this.browserbot.getCurrentWindow();
1845
// DGF normally you should use []s instead of eval "win."+attributeName
1846
// but in this case, attributeName may contain dots (e.g. document.title)
1847
// in that case, we have no choice but to use eval...
1848
if (PatternMatcher.matches(soughtAfterWindowPropertyValue, eval("this.browserbot.topWindow." + targetPropertyName))) {
1849
return this.browserbot.topWindow;
1851
for (windowName in selenium.browserbot.openedWindows) {
1852
var openedWindow = selenium.browserbot.openedWindows[windowName];
1853
if (PatternMatcher.matches(soughtAfterWindowPropertyValue, eval("openedWindow." + targetPropertyName))) {
1854
return openedWindow;
1857
throw new SeleniumError("could not find window with property " + targetPropertyName + " matching " + soughtAfterWindowPropertyValue);
1860
Selenium.prototype.doDragdrop = function(locator, movementsString) {
1861
/** deprecated - use dragAndDrop instead
1863
* @param locator an element locator
1864
* @param movementsString offset in pixels from the current location to which the element should be moved, e.g., "+70,-300"
1866
this.doDragAndDrop(locator, movementsString);
1869
Selenium.prototype.doSetMouseSpeed = function(pixels) {
1870
/** Configure the number of pixels between "mousemove" events during dragAndDrop commands (default=10).
1871
* <p>Setting this value to 0 means that we'll send a "mousemove" event to every single pixel
1872
* in between the start location and the end location; that can be very slow, and may
1873
* cause some browsers to force the JavaScript to timeout.</p>
1875
* <p>If the mouse speed is greater than the distance between the two dragged objects, we'll
1876
* just send one "mousemove" at the start location and then one final one at the end location.</p>
1877
* @param pixels the number of pixels between "mousemove" events
1879
var intValue = new Number(pixels);
1880
if (intValue.constructor != Number ||
1882
this.mouseSpeed = Selenium.DEFAULT_MOUSE_SPEED;
1884
this.mouseSpeed = pixels;
1888
Selenium.prototype.getMouseSpeed = function() {
1889
/** Returns the number of pixels between "mousemove" events during dragAndDrop commands (default=10).
1891
* @return number the number of pixels between "mousemove" events during dragAndDrop commands (default=10)
1893
return this.mouseSpeed;
1897
Selenium.prototype.doDragAndDrop = function(locator, movementsString) {
1898
/** Drags an element a certain distance and then drops it
1899
* @param locator an element locator
1900
* @param movementsString offset in pixels from the current location to which the element should be moved, e.g., "+70,-300"
1902
var element = this.browserbot.findElement(locator);
1903
var clientStartXY = getClientXY(element)
1904
var clientStartX = clientStartXY[0];
1905
var clientStartY = clientStartXY[1];
1907
var movements = movementsString.split(/,/);
1908
var movementX = Number(movements[0]);
1909
var movementY = Number(movements[1]);
1911
var clientFinishX = ((clientStartX + movementX) < 0) ? 0 : (clientStartX + movementX);
1912
var clientFinishY = ((clientStartY + movementY) < 0) ? 0 : (clientStartY + movementY);
1914
var mouseSpeed = this.mouseSpeed;
1915
var move = function(current, dest) {
1916
if (current == dest) return current;
1917
if (Math.abs(current - dest) < mouseSpeed) return dest;
1918
return (current < dest) ? current + mouseSpeed : current - mouseSpeed;
1921
this.browserbot.triggerMouseEvent(element, 'mousedown', true, clientStartX, clientStartY);
1922
this.browserbot.triggerMouseEvent(element, 'mousemove', true, clientStartX, clientStartY);
1923
var clientX = clientStartX;
1924
var clientY = clientStartY;
1926
while ((clientX != clientFinishX) || (clientY != clientFinishY)) {
1927
clientX = move(clientX, clientFinishX);
1928
clientY = move(clientY, clientFinishY);
1929
this.browserbot.triggerMouseEvent(element, 'mousemove', true, clientX, clientY);
1932
this.browserbot.triggerMouseEvent(element, 'mousemove', true, clientFinishX, clientFinishY);
1933
this.browserbot.triggerMouseEvent(element, 'mouseup', true, clientFinishX, clientFinishY);
1936
Selenium.prototype.doDragAndDropToObject = function(locatorOfObjectToBeDragged, locatorOfDragDestinationObject) {
1937
/** Drags an element and drops it on another element
1939
* @param locatorOfObjectToBeDragged an element to be dragged
1940
* @param locatorOfDragDestinationObject an element whose location (i.e., whose center-most pixel) will be the point where locatorOfObjectToBeDragged is dropped
1942
var startX = this.getElementPositionLeft(locatorOfObjectToBeDragged);
1943
var startY = this.getElementPositionTop(locatorOfObjectToBeDragged);
1945
var destinationLeftX = this.getElementPositionLeft(locatorOfDragDestinationObject);
1946
var destinationTopY = this.getElementPositionTop(locatorOfDragDestinationObject);
1947
var destinationWidth = this.getElementWidth(locatorOfDragDestinationObject);
1948
var destinationHeight = this.getElementHeight(locatorOfDragDestinationObject);
1950
var endX = Math.round(destinationLeftX + (destinationWidth / 2));
1951
var endY = Math.round(destinationTopY + (destinationHeight / 2));
1953
var deltaX = endX - startX;
1954
var deltaY = endY - startY;
1956
var movementsString = "" + deltaX + "," + deltaY;
1958
this.doDragAndDrop(locatorOfObjectToBeDragged, movementsString);
1961
Selenium.prototype.doWindowFocus = function() {
1962
/** Gives focus to the currently selected window
1965
this.browserbot.getCurrentWindow().focus();
1969
Selenium.prototype.doWindowMaximize = function() {
1970
/** Resize currently selected window to take up the entire screen
1973
var window = this.browserbot.getCurrentWindow();
1974
if (window!=null && window.screen) {
1976
window.resizeTo(screen.availWidth, screen.availHeight);
1980
Selenium.prototype.getAllWindowIds = function() {
1981
/** Returns the IDs of all windows that the browser knows about in an array.
1983
* @return string[] Array of identifiers of all windows that the browser knows about.
1985
return this.getAttributeFromAllWindows("id");
1988
Selenium.prototype.getAllWindowNames = function() {
1989
/** Returns the names of all windows that the browser knows about in an array.
1991
* @return string[] Array of names of all windows that the browser knows about.
1993
return this.getAttributeFromAllWindows("name");
1996
Selenium.prototype.getAllWindowTitles = function() {
1997
/** Returns the titles of all windows that the browser knows about in an array.
1999
* @return string[] Array of titles of all windows that the browser knows about.
2001
return this.getAttributeFromAllWindows("document.title");
2004
Selenium.prototype.getHtmlSource = function() {
2005
/** Returns the entire HTML source between the opening and
2006
* closing "html" tags.
2008
* @return string the entire HTML source
2010
return this.browserbot.getDocument().getElementsByTagName("html")[0].innerHTML;
2013
Selenium.prototype.doSetCursorPosition = function(locator, position) {
2015
* Moves the text cursor to the specified position in the given input element or textarea.
2016
* This method will fail if the specified element isn't an input element or textarea.
2018
* @param locator an <a href="#locators">element locator</a> pointing to an input element or textarea
2019
* @param position the numerical position of the cursor in the field; position should be 0 to move the position to the beginning of the field. You can also set the cursor to -1 to move it to the end of the field.
2021
var element = this.browserbot.findElement(locator);
2022
if (element.value == undefined) {
2023
Assert.fail("Element " + locator + " is not an input.");
2025
if (position == -1) {
2026
position = element.value.length;
2029
if( element.setSelectionRange && !browserVersion.isOpera) {
2031
element.setSelectionRange(/*start*/position,/*end*/position);
2033
else if( element.createTextRange ) {
2034
triggerEvent(element, 'focus', false);
2035
var range = element.createTextRange();
2036
range.collapse(true);
2037
range.moveEnd('character',position);
2038
range.moveStart('character',position);
2043
Selenium.prototype.getElementIndex = function(locator) {
2045
* Get the relative index of an element to its parent (starting from 0). The comment node and empty text node
2048
* @param locator an <a href="#locators">element locator</a> pointing to an element
2049
* @return number of relative index of the element to its parent (starting from 0)
2051
var element = this.browserbot.findElement(locator);
2052
var previousSibling;
2054
while ((previousSibling = element.previousSibling) != null) {
2055
if (!this._isCommentOrEmptyTextNode(previousSibling)) {
2058
element = previousSibling;
2063
Selenium.prototype.isOrdered = function(locator1, locator2) {
2065
* Check if these two elements have same parent and are ordered siblings in the DOM. Two same elements will
2066
* not be considered ordered.
2068
* @param locator1 an <a href="#locators">element locator</a> pointing to the first element
2069
* @param locator2 an <a href="#locators">element locator</a> pointing to the second element
2070
* @return boolean true if element1 is the previous sibling of element2, false otherwise
2072
var element1 = this.browserbot.findElement(locator1);
2073
var element2 = this.browserbot.findElement(locator2);
2074
if (element1 === element2) return false;
2076
var previousSibling;
2077
while ((previousSibling = element2.previousSibling) != null) {
2078
if (previousSibling === element1) {
2081
element2 = previousSibling;
2086
Selenium.prototype._isCommentOrEmptyTextNode = function(node) {
2087
return node.nodeType == 8 || ((node.nodeType == 3) && !(/[^\t\n\r ]/.test(node.data)));
2090
Selenium.prototype.getElementPositionLeft = function(locator) {
2092
* Retrieves the horizontal position of an element
2094
* @param locator an <a href="#locators">element locator</a> pointing to an element OR an element itself
2095
* @return number of pixels from the edge of the frame.
2098
if ("string"==typeof locator) {
2099
element = this.browserbot.findElement(locator);
2104
var x = element.offsetLeft;
2105
var elementParent = element.offsetParent;
2107
while (elementParent != null)
2111
if( (elementParent.tagName != "TABLE") && (elementParent.tagName != "BODY") )
2113
x += elementParent.clientLeft;
2116
else // Netscape/DOM
2118
if(elementParent.tagName == "TABLE")
2120
var parentBorder = parseInt(elementParent.border);
2121
if(isNaN(parentBorder))
2123
var parentFrame = elementParent.getAttribute('frame');
2124
if(parentFrame != null)
2129
else if(parentBorder > 0)
2135
x += elementParent.offsetLeft;
2136
elementParent = elementParent.offsetParent;
2141
Selenium.prototype.getElementPositionTop = function(locator) {
2143
* Retrieves the vertical position of an element
2145
* @param locator an <a href="#locators">element locator</a> pointing to an element OR an element itself
2146
* @return number of pixels from the edge of the frame.
2149
if ("string"==typeof locator) {
2150
element = this.browserbot.findElement(locator);
2158
while (element != null)
2162
if( (element.tagName != "TABLE") && (element.tagName != "BODY") )
2164
y += element.clientTop;
2167
else // Netscape/DOM
2169
if(element.tagName == "TABLE")
2171
var parentBorder = parseInt(element.border);
2172
if(isNaN(parentBorder))
2174
var parentFrame = element.getAttribute('frame');
2175
if(parentFrame != null)
2180
else if(parentBorder > 0)
2186
y += element.offsetTop;
2188
// Netscape can get confused in some cases, such that the height of the parent is smaller
2189
// than that of the element (which it shouldn't really be). If this is the case, we need to
2190
// exclude this element, since it will result in too large a 'top' return value.
2191
if (element.offsetParent && element.offsetParent.offsetHeight && element.offsetParent.offsetHeight < element.offsetHeight)
2193
// skip the parent that's too small
2194
element = element.offsetParent.offsetParent;
2199
element = element.offsetParent;
2205
Selenium.prototype.getElementWidth = function(locator) {
2207
* Retrieves the width of an element
2209
* @param locator an <a href="#locators">element locator</a> pointing to an element
2210
* @return number width of an element in pixels
2212
var element = this.browserbot.findElement(locator);
2213
return element.offsetWidth;
2216
Selenium.prototype.getElementHeight = function(locator) {
2218
* Retrieves the height of an element
2220
* @param locator an <a href="#locators">element locator</a> pointing to an element
2221
* @return number height of an element in pixels
2223
var element = this.browserbot.findElement(locator);
2224
return element.offsetHeight;
2227
Selenium.prototype.getCursorPosition = function(locator) {
2229
* Retrieves the text cursor position in the given input element or textarea; beware, this may not work perfectly on all browsers.
2231
* <p>Specifically, if the cursor/selection has been cleared by JavaScript, this command will tend to
2232
* return the position of the last location of the cursor, even though the cursor is now gone from the page. This is filed as <a href="http://jira.openqa.org/browse/SEL-243">SEL-243</a>.</p>
2233
* This method will fail if the specified element isn't an input element or textarea, or there is no cursor in the element.
2235
* @param locator an <a href="#locators">element locator</a> pointing to an input element or textarea
2236
* @return number the numerical position of the cursor in the field
2238
var element = this.browserbot.findElement(locator);
2239
var doc = this.browserbot.getDocument();
2240
var win = this.browserbot.getCurrentWindow();
2241
if( doc.selection && !browserVersion.isOpera){
2243
var selectRange = doc.selection.createRange().duplicate();
2244
var elementRange = element.createTextRange();
2245
selectRange.move("character",0);
2246
elementRange.move("character",0);
2247
var inRange1 = selectRange.inRange(elementRange);
2248
var inRange2 = elementRange.inRange(selectRange);
2249
elementRange.setEndPoint("EndToEnd", selectRange);
2251
Assert.fail("There is no cursor on this page!");
2253
var answer = String(elementRange.text).replace(/\r/g,"").length;
2256
if (typeof(element.selectionStart) != "undefined") {
2257
if (win.getSelection && typeof(win.getSelection().rangeCount) != undefined && win.getSelection().rangeCount == 0) {
2258
Assert.fail("There is no cursor on this page!");
2260
return element.selectionStart;
2263
throw new Error("Couldn't detect cursor position on this browser!");
2267
Selenium.prototype.getExpression = function(expression) {
2269
* Returns the specified expression.
2271
* <p>This is useful because of JavaScript preprocessing.
2272
* It is used to generate commands like assertExpression and waitForExpression.</p>
2274
* @param expression the value to return
2275
* @return string the value passed in
2280
Selenium.prototype.getXpathCount = function(xpath) {
2282
* Returns the number of nodes that match the specified xpath, eg. "//table" would give
2283
* the number of tables.
2285
* @param xpath the xpath expression to evaluate. do NOT wrap this expression in a 'count()' function; we will do that for you.
2286
* @return number the number of nodes that match the specified xpath
2288
var result = this.browserbot.evaluateXPathCount(xpath, this.browserbot.getDocument());
2292
Selenium.prototype.doAssignId = function(locator, identifier) {
2294
* Temporarily sets the "id" attribute of the specified element, so you can locate it in the future
2295
* using its ID rather than a slow/complicated XPath. This ID will disappear once the page is
2297
* @param locator an <a href="#locators">element locator</a> pointing to an element
2298
* @param identifier a string to be used as the ID of the specified element
2300
var element = this.browserbot.findElement(locator);
2301
element.id = identifier;
2304
Selenium.prototype.doAllowNativeXpath = function(allow) {
2306
* Specifies whether Selenium should use the native in-browser implementation
2307
* of XPath (if any native version is available); if you pass "false" to
2308
* this function, we will always use our pure-JavaScript xpath library.
2309
* Using the pure-JS xpath library can improve the consistency of xpath
2310
* element locators between different browser vendors, but the pure-JS
2311
* version is much slower than the native implementations.
2312
* @param allow boolean, true means we'll prefer to use native XPath; false means we'll only use JS XPath
2314
if ("false" == allow || "0" == allow) { // The strings "false" and "0" are true values in JS
2317
this.browserbot.allowNativeXpath = allow;
2320
Selenium.prototype.doIgnoreAttributesWithoutValue = function(ignore) {
2322
* Specifies whether Selenium will ignore xpath attributes that have no
2323
* value, i.e. are the empty string, when using the non-native xpath
2324
* evaluation engine. You'd want to do this for performance reasons in IE.
2325
* However, this could break certain xpaths, for example an xpath that looks
2326
* for an attribute whose value is NOT the empty string.
2328
* The hope is that such xpaths are relatively rare, but the user should
2329
* have the option of using them. Note that this only influences xpath
2330
* evaluation when using the ajaxslt engine (i.e. not "javascript-xpath").
2332
* @param ignore boolean, true means we'll ignore attributes without value
2333
* at the expense of xpath "correctness"; false means
2334
* we'll sacrifice speed for correctness.
2336
if ('false' == ignore || '0' == ignore) {
2339
this.browserbot.ignoreAttributesWithoutValue = ignore;
2342
Selenium.prototype.doWaitForCondition = function(script, timeout) {
2344
* Runs the specified JavaScript snippet repeatedly until it evaluates to "true".
2345
* The snippet may have multiple lines, but only the result of the last line
2346
* will be considered.
2348
* <p>Note that, by default, the snippet will be run in the runner's test window, not in the window
2349
* of your application. To get the window of your application, you can use
2350
* the JavaScript snippet <code>selenium.browserbot.getCurrentWindow()</code>, and then
2351
* run your JavaScript in there</p>
2352
* @param script the JavaScript snippet to run
2353
* @param timeout a timeout in milliseconds, after which this command will return with an error
2356
return Selenium.decorateFunctionWithTimeout(function () {
2357
var window = selenium.browserbot.getCurrentWindow();
2358
return eval(script);
2362
Selenium.prototype.doWaitForCondition.dontCheckAlertsAndConfirms = true;
2364
Selenium.prototype.doSetTimeout = function(timeout) {
2366
* Specifies the amount of time that Selenium will wait for actions to complete.
2368
* <p>Actions that require waiting include "open" and the "waitFor*" actions.</p>
2369
* The default timeout is 30 seconds.
2370
* @param timeout a timeout in milliseconds, after which the action will return with an error
2373
timeout = Selenium.DEFAULT_TIMEOUT;
2375
this.defaultTimeout = timeout;
2378
Selenium.prototype.doWaitForPageToLoad = function(timeout) {
2380
* Waits for a new page to load.
2382
* <p>You can use this command instead of the "AndWait" suffixes, "clickAndWait", "selectAndWait", "typeAndWait" etc.
2383
* (which are only available in the JS API).</p>
2385
* <p>Selenium constantly keeps track of new pages loading, and sets a "newPageLoaded"
2386
* flag when it first notices a page load. Running any other Selenium command after
2387
* turns the flag to false. Hence, if you want to wait for a page to load, you must
2388
* wait immediately after a Selenium command that caused a page-load.</p>
2389
* @param timeout a timeout in milliseconds, after which this command will return with an error
2391
// in pi-mode, the test and the harness share the window; thus if we are executing this code, then we have loaded
2392
if (window["proxyInjectionMode"] == null || !window["proxyInjectionMode"]) {
2393
return this.makePageLoadCondition(timeout);
2397
Selenium.prototype.doWaitForFrameToLoad = function(frameAddress, timeout) {
2399
* Waits for a new frame to load.
2401
* <p>Selenium constantly keeps track of new pages and frames loading,
2402
* and sets a "newPageLoaded" flag when it first notices a page load.</p>
2404
* See waitForPageToLoad for more information.
2406
* @param frameAddress FrameAddress from the server side
2407
* @param timeout a timeout in milliseconds, after which this command will return with an error
2409
// in pi-mode, the test and the harness share the window; thus if we are executing this code, then we have loaded
2410
if (window["proxyInjectionMode"] == null || !window["proxyInjectionMode"]) {
2411
return this.makePageLoadCondition(timeout);
2415
Selenium.prototype._isNewPageLoaded = function() {
2416
return this.browserbot.isNewPageLoaded();
2419
Selenium.prototype.doWaitForPageToLoad.dontCheckAlertsAndConfirms = true;
2422
* Evaluate a parameter, performing JavaScript evaluation and variable substitution.
2423
* If the string matches the pattern "javascript{ ... }", evaluate the string between the braces.
2425
Selenium.prototype.preprocessParameter = function(value) {
2426
var match = value.match(/^javascript\{((.|\r?\n)+)\}$/);
2427
if (match && match[1]) {
2428
return eval(match[1]).toString();
2430
return this.replaceVariables(value);
2434
* Search through str and replace all variable references ${varName} with their
2435
* value in storedVars.
2437
Selenium.prototype.replaceVariables = function(str) {
2438
var stringResult = str;
2440
// Find all of the matching variable references
2441
var match = stringResult.match(/\$\{\w+\}/g);
2443
return stringResult;
2446
// For each match, lookup the variable value, and replace if found
2447
for (var i = 0; match && i < match.length; i++) {
2448
var variable = match[i]; // The replacement variable, with ${}
2449
var name = variable.substring(2, variable.length - 1); // The replacement variable without ${}
2450
var replacement = storedVars[name];
2451
if (replacement != undefined) {
2452
stringResult = stringResult.replace(variable, replacement);
2455
return stringResult;
2458
Selenium.prototype.getCookie = function() {
2460
* Return all cookies of the current page under test.
2462
* @return string all cookies of the current page under test
2464
var doc = this.browserbot.getDocument();
2468
Selenium.prototype.getCookieByName = function(name) {
2470
* Returns the value of the cookie with the specified name, or throws an error if the cookie is not present.
2471
* @param name the name of the cookie
2472
* @return string the value of the cookie
2474
var v = this.browserbot.getCookieByName(name);
2476
throw new SeleniumError("Cookie '"+name+"' was not found");
2481
Selenium.prototype.isCookiePresent = function(name) {
2483
* Returns true if a cookie with the specified name is present, or false otherwise.
2484
* @param name the name of the cookie
2485
* @return boolean true if a cookie with the specified name is present, or false otherwise.
2487
var v = this.browserbot.getCookieByName(name);
2488
var absent = (v === null);
2492
Selenium.prototype.doCreateCookie = function(nameValuePair, optionsString) {
2494
* Create a new cookie whose path and domain are same with those of current page
2495
* under test, unless you specified a path for this cookie explicitly.
2497
* @param nameValuePair name and value of the cookie in a format "name=value"
2498
* @param optionsString options for the cookie. Currently supported options include 'path', 'max_age' and 'domain'.
2499
* the optionsString's format is "path=/path/, max_age=60, domain=.foo.com". The order of options are irrelevant, the unit
2500
* of the value of 'max_age' is second. Note that specifying a domain that isn't a subset of the current domain will
2503
var results = /[^\s=\[\]\(\),"\/\?@:;]+=[^\s=\[\]\(\),"\/\?@:;]*/.test(nameValuePair);
2505
throw new SeleniumError("Invalid parameter.");
2507
var cookie = nameValuePair.trim();
2508
results = /max_age=(\d+)/.exec(optionsString);
2510
var expireDateInMilliseconds = (new Date()).getTime() + results[1] * 1000;
2511
cookie += "; expires=" + new Date(expireDateInMilliseconds).toGMTString();
2513
results = /path=([^\s,]+)[,]?/.exec(optionsString);
2515
var path = results[1];
2516
if (browserVersion.khtml) {
2517
// Safari and conquerer don't like paths with / at the end
2519
path = path.replace(/\/$/, "");
2522
cookie += "; path=" + path;
2524
results = /domain=([^\s,]+)[,]?/.exec(optionsString);
2526
var domain = results[1];
2527
cookie += "; domain=" + domain;
2529
LOG.debug("Setting cookie to: " + cookie);
2530
this.browserbot.getDocument().cookie = cookie;
2533
Selenium.prototype.doDeleteCookie = function(name,optionsString) {
2535
* Delete a named cookie with specified path and domain. Be careful; to delete a cookie, you
2536
* need to delete it using the exact same path and domain that were used to create the cookie.
2537
* If the path is wrong, or the domain is wrong, the cookie simply won't be deleted. Also
2538
* note that specifying a domain that isn't a subset of the current domain will usually fail.
2540
* Since there's no way to discover at runtime the original path and domain of a given cookie,
2541
* we've added an option called 'recurse' to try all sub-domains of the current domain with
2542
* all paths that are a subset of the current path. Beware; this option can be slow. In
2543
* big-O notation, it operates in O(n*m) time, where n is the number of dots in the domain
2544
* name and m is the number of slashes in the path.
2546
* @param name the name of the cookie to be deleted
2547
* @param optionsString options for the cookie. Currently supported options include 'path', 'domain'
2548
* and 'recurse.' The optionsString's format is "path=/path/, domain=.foo.com, recurse=true".
2549
* The order of options are irrelevant. Note that specifying a domain that isn't a subset of
2550
* the current domain will usually fail.
2552
// set the expire time of the cookie to be deleted to one minute before now.
2555
var recurse = false;
2556
var matched = false;
2557
results = /path=([^\s,]+)[,]?/.exec(optionsString);
2562
results = /domain=([^\s,]+)[,]?/.exec(optionsString);
2565
domain = results[1];
2567
results = /recurse=([^\s,]+)[,]?/.exec(optionsString);
2570
recurse = results[1];
2571
if ("false" == recurse) {
2575
// Treat the entire optionsString as a path (for backwards compatibility)
2576
if (optionsString && !matched) {
2577
LOG.warn("Using entire optionsString as a path; please change the argument to deleteCookie to use path="+optionsString);
2578
path = optionsString;
2580
if (browserVersion.khtml) {
2581
// Safari and conquerer don't like paths with / at the end
2583
path = path.replace(/\/$/, "");
2587
domain = domain.trim();
2588
var cookieName = name.trim();
2590
this.browserbot.recursivelyDeleteCookie(cookieName, domain, path);
2592
this.browserbot.deleteCookie(cookieName, domain, path);
2596
Selenium.prototype.doDeleteAllVisibleCookies = function() {
2597
/** Calls deleteCookie with recurse=true on all cookies visible to the current page.
2598
* As noted on the documentation for deleteCookie, recurse=true can be much slower
2599
* than simply deleting the cookies using a known domain/path.
2601
var win = this.browserbot.getCurrentWindow();
2602
var doc = win.document;
2603
var cookieNames = this.browserbot.getAllCookieNames(doc);
2604
var domain = doc.domain;
2605
var path = win.location.pathname;
2606
for (var i = 0; i < cookieNames.length; i++) {
2607
this.browserbot.recursivelyDeleteCookie(cookieNames[i], domain, path, win);
2611
Selenium.prototype.doSetBrowserLogLevel = function(logLevel) {
2613
* Sets the threshold for browser-side logging messages; log messages beneath this threshold will be discarded.
2614
* Valid logLevel strings are: "debug", "info", "warn", "error" or "off".
2615
* To see the browser logs, you need to
2616
* either show the log window in GUI mode, or enable browser-side logging in Selenium RC.
2618
* @param logLevel one of the following: "debug", "info", "warn", "error" or "off"
2620
if (logLevel == null || logLevel == "") {
2621
throw new SeleniumError("You must specify a log level");
2623
logLevel = logLevel.toLowerCase();
2624
if (LOG.logLevels[logLevel] == null) {
2625
throw new SeleniumError("Invalid log level: " + logLevel);
2627
LOG.setLogLevelThreshold(logLevel);
2630
Selenium.prototype.doRunScript = function(script) {
2632
* Creates a new "script" tag in the body of the current test window, and
2633
* adds the specified text into the body of the command. Scripts run in
2634
* this way can often be debugged more easily than scripts executed using
2635
* Selenium's "getEval" command. Beware that JS exceptions thrown in these script
2636
* tags aren't managed by Selenium, so you should probably wrap your script
2637
* in try/catch blocks if there is any chance that the script will throw
2639
* @param script the JavaScript snippet to run
2641
var win = this.browserbot.getCurrentWindow();
2642
var doc = win.document;
2643
var scriptTag = doc.createElement("script");
2644
scriptTag.type = "text/javascript"
2645
scriptTag.text = script;
2646
doc.body.appendChild(scriptTag);
2649
Selenium.prototype.doAddLocationStrategy = function(strategyName, functionDefinition) {
2651
* Defines a new function for Selenium to locate elements on the page.
2653
* if you define the strategy "foo", and someone runs click("foo=blah"), we'll
2654
* run your function, passing you the string "blah", and click on the element
2655
* that your function
2656
* returns, or throw an "Element not found" error if your function returns null.
2658
* We'll pass three arguments to your function:
2660
* <li>locator: the string the user passed in</li>
2661
* <li>inWindow: the currently selected window</li>
2662
* <li>inDocument: the currently selected document</li>
2664
* The function must return null if the element can't be found.
2666
* @param strategyName the name of the strategy to define; this should use only
2667
* letters [a-zA-Z] with no spaces or other punctuation.
2668
* @param functionDefinition a string defining the body of a function in JavaScript.
2669
* For example: <code>return inDocument.getElementById(locator);</code>
2671
if (!/^[a-zA-Z]+$/.test(strategyName)) {
2672
throw new SeleniumError("Invalid strategy name: " + strategyName);
2674
var strategyFunction;
2676
strategyFunction = new Function("locator", "inDocument", "inWindow", functionDefinition);
2678
throw new SeleniumError("Error evaluating function definition: " + extractExceptionMessage(ex));
2680
var safeStrategyFunction = function() {
2682
return strategyFunction.apply(this, arguments);
2684
throw new SeleniumError("Error executing strategy function " + strategyName + ": " + extractExceptionMessage(ex));
2687
this.browserbot.locationStrategies[strategyName] = safeStrategyFunction;
2690
Selenium.prototype.doCaptureEntirePageScreenshot = function(filename, kwargs) {
2692
* Saves the entire contents of the current window canvas to a PNG file.
2693
* Contrast this with the captureScreenshot command, which captures the
2694
* contents of the OS viewport (i.e. whatever is currently being displayed
2695
* on the monitor), and is implemented in the RC only. Currently this only
2696
* works in Firefox when running in chrome mode, and in IE non-HTA using
2697
* the EXPERIMENTAL "Snapsie" utility. The Firefox implementation is mostly
2698
* borrowed from the Screengrab! Firefox extension. Please see
2699
* http://www.screengrab.org and http://snapsie.sourceforge.net/ for
2702
* @param filename the path to the file to persist the screenshot as. No
2703
* filename extension will be appended by default.
2704
* Directories will not be created if they do not exist,
2705
* and an exception will be thrown, possibly by native
2707
* @param kwargs a kwargs string that modifies the way the screenshot
2708
* is captured. Example: "background=#CCFFDD" .
2709
* Currently valid options:
2711
* <dt>background</dt>
2712
* <dd>the background CSS for the HTML document. This
2713
* may be useful to set for capturing screenshots of
2714
* less-than-ideal layouts, for example where absolute
2715
* positioning causes the calculation of the canvas
2716
* dimension to fail and a black background is exposed
2717
* (possibly obscuring black text).</dd>
2720
if (! browserVersion.isChrome &&
2721
! (browserVersion.isIE && ! browserVersion.isHTA)) {
2722
throw new SeleniumError('captureEntirePageScreenshot is only '
2723
+ 'implemented for Firefox ("firefox" or "chrome", NOT '
2724
+ '"firefoxproxy") and IE non-HTA ("iexploreproxy", NOT "iexplore" '
2725
+ 'or "iehta"). The current browser isn\'t one of them!');
2728
// do or do not ... there is no try
2730
if (browserVersion.isIE) {
2731
// targeting snapsIE >= 0.2
2732
function getFailureMessage(exceptionMessage) {
2733
var msg = 'Snapsie failed: ';
2734
if (exceptionMessage) {
2735
if (exceptionMessage ==
2736
"Automation server can't create object") {
2737
msg += 'Is it installed? Does it have permission to run '
2738
+ 'as an add-on? See http://snapsie.sourceforge.net/';
2741
msg += exceptionMessage;
2745
msg += 'Undocumented error';
2750
if (typeof(runOptions) != 'undefined' &&
2751
runOptions.isMultiWindowMode() == false) {
2754
new Snapsie().saveSnapshot(filename, 'selenium_myiframe');
2757
throw new SeleniumError(getFailureMessage(e.message));
2761
// multi-window mode
2762
if (!this.snapsieSrc) {
2763
// XXX - cache snapsie, and capture the screenshot as a
2764
// callback. Definitely a hack, because we may be late taking
2765
// the first screenshot, but saves us from polluting other code
2766
// for now. I wish there were an easier way to get at the
2767
// contents of a referenced script!
2768
var snapsieUrl = (this.browserbot.buttonWindow.location.href)
2769
.replace(/(Test|Remote)Runner\.html/, 'lib/snapsie.js');
2771
new Ajax.Request(snapsieUrl, {
2773
, onSuccess: function(transport) {
2774
self.snapsieSrc = transport.responseText;
2775
self.doCaptureEntirePageScreenshot(filename, kwargs);
2781
// it's going into a string, so escape the backslashes
2782
filename = filename.replace(/\\/g, '\\\\');
2784
// this is sort of hackish. We insert a script into the document,
2785
// and remove it before anyone notices.
2786
var doc = selenium.browserbot.getDocument();
2787
var script = doc.createElement('script');
2788
var scriptContent = this.snapsieSrc
2790
+ ' new Snapsie().saveSnapshot("' + filename + '");'
2793
+ ' document.getElementById("takeScreenshot").failure ='
2796
script.id = 'takeScreenshot';
2797
script.language = 'javascript';
2798
script.text = scriptContent;
2799
doc.body.appendChild(script);
2800
script.parentNode.removeChild(script);
2801
if (script.failure) {
2802
throw new SeleniumError(getFailureMessage(script.failure));
2809
prepareCanvas: function(width, height) {
2810
var styleWidth = width + 'px';
2811
var styleHeight = height + 'px';
2813
var grabCanvas = document.getElementById('screenshot_canvas');
2815
// create the canvas
2816
var ns = 'http://www.w3.org/1999/xhtml';
2817
grabCanvas = document.createElementNS(ns, 'html:canvas');
2818
grabCanvas.id = 'screenshot_canvas';
2819
grabCanvas.style.display = 'none';
2820
document.documentElement.appendChild(grabCanvas);
2823
grabCanvas.width = width;
2824
grabCanvas.style.width = styleWidth;
2825
grabCanvas.style.maxWidth = styleWidth;
2826
grabCanvas.height = height;
2827
grabCanvas.style.height = styleHeight;
2828
grabCanvas.style.maxHeight = styleHeight;
2833
prepareContext: function(canvas, box) {
2834
var context = canvas.getContext('2d');
2835
context.clearRect(box.x, box.y, box.width, box.height);
2842
dataUrlToBinaryInputStream: function(dataUrl) {
2843
var nsIoService = Components.classes["@mozilla.org/network/io-service;1"]
2844
.getService(Components.interfaces.nsIIOService);
2845
var channel = nsIoService
2846
.newChannelFromURI(nsIoService.newURI(dataUrl, null, null));
2847
var binaryInputStream = Components.classes["@mozilla.org/binaryinputstream;1"]
2848
.createInstance(Components.interfaces.nsIBinaryInputStream);
2850
binaryInputStream.setInputStream(channel.open());
2851
return binaryInputStream;
2854
newFileOutputStream: function(nsFile) {
2855
var writeFlag = 0x02; // write only
2856
var createFlag = 0x08; // create
2857
var truncateFlag = 0x20; // truncate
2858
var fileOutputStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
2859
.createInstance(Components.interfaces.nsIFileOutputStream);
2861
fileOutputStream.init(nsFile,
2862
writeFlag | createFlag | truncateFlag, 0664, null);
2863
return fileOutputStream;
2866
writeBinaryInputStreamToFileOutputStream:
2867
function(binaryInputStream, fileOutputStream) {
2868
var numBytes = binaryInputStream.available();
2869
var bytes = binaryInputStream.readBytes(numBytes);
2870
fileOutputStream.write(bytes, numBytes);
2874
// compute dimensions
2875
var window = this.browserbot.getCurrentWindow();
2876
var doc = window.document.documentElement;
2880
width: doc.scrollWidth,
2881
height: doc.scrollHeight
2883
LOG.debug('computed dimensions');
2885
var originalBackground = doc.style.background;
2888
var args = parse_kwargs(kwargs);
2889
if (args.background) {
2890
doc.style.background = args.background;
2896
var canvas = grabber.prepareCanvas(box.width, box.height);
2897
var context = grabber.prepareContext(canvas, box);
2898
context.drawWindow(window, box.x, box.y, box.width, box.height,
2901
var dataUrl = canvas.toDataURL("image/" + format);
2902
LOG.debug('grabbed to canvas');
2904
doc.style.background = originalBackground;
2907
var nsFile = Components.classes["@mozilla.org/file/local;1"]
2908
.createInstance(Components.interfaces.nsILocalFile);
2910
nsFile.initWithPath(filename);
2913
if (/NS_ERROR_FILE_UNRECOGNIZED_PATH/.test(e.message)) {
2914
// try using the opposite file separator
2915
if (filename.indexOf('/') != -1) {
2916
filename = filename.replace(/\//g, '\\');
2919
filename = filename.replace(/\\/g, '/');
2921
nsFile.initWithPath(filename);
2927
var binaryInputStream = SGNsUtils.dataUrlToBinaryInputStream(dataUrl);
2928
var fileOutputStream = SGNsUtils.newFileOutputStream(nsFile);
2929
SGNsUtils.writeBinaryInputStreamToFileOutputStream(binaryInputStream,
2931
fileOutputStream.close();
2932
LOG.debug('saved to file');
2935
Selenium.prototype.doRollup = function(rollupName, kwargs) {
2937
* Executes a command rollup, which is a series of commands with a unique
2938
* name, and optionally arguments that control the generation of the set of
2939
* commands. If any one of the rolled-up commands fails, the rollup is
2940
* considered to have failed. Rollups may also contain nested rollups.
2942
* @param rollupName the name of the rollup command
2943
* @param kwargs keyword arguments string that influences how the
2944
* rollup expands into commands
2946
// we have to temporarily hijack the commandStarted, nextCommand(),
2947
// commandComplete(), and commandError() methods of the TestLoop object.
2948
// When the expanded rollup commands are done executing (or an error has
2949
// occurred), we'll restore them to their original values.
2950
var loop = currentTest || htmlTestRunner.currentTest;
2951
var backupManager = {
2952
backup: function() {
2953
for (var item in this.data) {
2954
this.data[item] = loop[item];
2957
, restore: function() {
2958
for (var item in this.data) {
2959
loop[item] = this.data[item];
2963
requiresCallBack: null
2964
, commandStarted: null
2966
, commandComplete: null
2967
, commandError: null
2968
, pendingRollupCommands: null
2969
, rollupFailed: null
2970
, rollupFailedMessage: null
2974
var rule = RollupManager.getInstance().getRollupRule(rollupName);
2975
var expandedCommands = rule.getExpandedCommands(kwargs);
2977
// hold your breath ...
2979
backupManager.backup();
2980
loop.requiresCallBack = false;
2981
loop.commandStarted = function() {};
2982
loop.nextCommand = function() {
2983
if (this.pendingRollupCommands.length == 0) {
2986
var command = this.pendingRollupCommands.shift();
2989
loop.commandComplete = function(result) {
2990
if (result.failed) {
2991
this.rollupFailed = true;
2992
this.rollupFailureMessages.push(result.failureMessage);
2995
if (this.pendingRollupCommands.length == 0) {
2997
failed: this.rollupFailed
2998
, failureMessage: this.rollupFailureMessages.join('; ')
3000
LOG.info('Rollup execution complete: ' + (result.failed
3001
? 'failed! (see error messages below)' : 'ok'));
3002
backupManager.restore();
3003
this.commandComplete(result);
3006
loop.commandError = function(errorMessage) {
3007
LOG.info('Rollup execution complete: bombed!');
3008
backupManager.restore();
3009
this.commandError(errorMessage);
3012
loop.pendingRollupCommands = expandedCommands;
3013
loop.rollupFailed = false;
3014
loop.rollupFailureMessages = [];
3017
LOG.error('Rollup error: ' + e);
3018
backupManager.restore();
3022
Selenium.prototype.doAddScript = function(scriptContent, scriptTagId) {
3024
* Loads script content into a new script tag in the Selenium document. This
3025
* differs from the runScript command in that runScript adds the script tag
3026
* to the document of the AUT, not the Selenium document. The following
3027
* entities in the script content are replaced by the characters they
3034
* The corresponding remove command is removeScript.
3036
* @param scriptContent the Javascript content of the script to add
3037
* @param scriptTagId (optional) the id of the new script tag. If
3038
* specified, and an element with this id already
3039
* exists, this operation will fail.
3041
if (scriptTagId && document.getElementById(scriptTagId)) {
3042
var msg = "Element with id '" + scriptTagId + "' already exists!";
3043
throw new SeleniumError(msg);
3046
var head = document.getElementsByTagName('head')[0];
3047
var script = document.createElement('script');
3049
script.type = 'text/javascript';
3052
script.id = scriptTagId;
3055
// replace some entities
3056
scriptContent = scriptContent
3057
.replace(/</g, '<')
3058
.replace(/>/g, '>')
3059
.replace(/&/g, '&');
3061
script.text = scriptContent;
3062
head.appendChild(script);
3065
Selenium.prototype.doRemoveScript = function(scriptTagId) {
3067
* Removes a script tag from the Selenium document identified by the given
3068
* id. Does nothing if the referenced tag doesn't exist.
3070
* @param scriptTagId the id of the script element to remove.
3072
var script = document.getElementById(scriptTagId);
3074
if (script && getTagName(script) == 'script') {
3075
script.parentNode.removeChild(script);
3079
Selenium.prototype.doUseXpathLibrary = function(libraryName) {
3081
* Allows choice of one of the available libraries.
3082
* @param libraryName name of the desired library
3083
* Only the following three can be chosen:
3085
* <li>"ajaxslt" - Google's library</li>
3086
* <li>"javascript-xpath" - Cybozu Labs' faster library</li>
3087
* <li>"default" - The default library. Currently the default library is "ajaxslt" .</li>
3089
* If libraryName isn't one of these three, then
3090
* no change will be made.
3094
if (libraryName == "default") {
3095
this.browserbot.xpathLibrary = this.browserbot.defaultXpathLibrary;
3099
if ((libraryName != 'ajaxslt') && (libraryName != 'javascript-xpath')) {
3103
this.browserbot.xpathLibrary = libraryName;
3108
* Factory for creating "Option Locators".
3109
* An OptionLocator is an object for dealing with Select options (e.g. for
3110
* finding a specified option, or asserting that the selected option of
3111
* Select element matches some condition.
3112
* The type of locator returned by the factory depends on the locator string:
3113
* label=<exp> (OptionLocatorByLabel)
3114
* value=<exp> (OptionLocatorByValue)
3115
* index=<exp> (OptionLocatorByIndex)
3116
* id=<exp> (OptionLocatorById)
3117
* <exp> (default is OptionLocatorByLabel).
3119
function OptionLocatorFactory() {
3122
OptionLocatorFactory.prototype.fromLocatorString = function(locatorString) {
3123
var locatorType = 'label';
3124
var locatorValue = locatorString;
3125
// If there is a locator prefix, use the specified strategy
3126
var result = locatorString.match(/^([a-zA-Z]+)=(.*)/);
3128
locatorType = result[1];
3129
locatorValue = result[2];
3131
if (this.optionLocators == undefined) {
3132
this.registerOptionLocators();
3134
if (this.optionLocators[locatorType]) {
3135
return new this.optionLocators[locatorType](locatorValue);
3137
throw new SeleniumError("Unknown option locator type: " + locatorType);
3141
* To allow for easy extension, all of the option locators are found by
3142
* searching for all methods of OptionLocatorFactory.prototype that start
3143
* with "OptionLocatorBy".
3144
* TODO: Consider using the term "Option Specifier" instead of "Option Locator".
3146
OptionLocatorFactory.prototype.registerOptionLocators = function() {
3147
this.optionLocators={};
3148
for (var functionName in this) {
3149
var result = /OptionLocatorBy([A-Z].+)$/.exec(functionName);
3150
if (result != null) {
3151
var locatorName = result[1].lcfirst();
3152
this.optionLocators[locatorName] = this[functionName];
3158
* OptionLocator for options identified by their labels.
3160
OptionLocatorFactory.prototype.OptionLocatorByLabel = function(label) {
3162
this.labelMatcher = new PatternMatcher(this.label);
3163
this.findOption = function(element) {
3164
for (var i = 0; i < element.options.length; i++) {
3165
if (this.labelMatcher.matches(element.options[i].text)) {
3166
return element.options[i];
3169
throw new SeleniumError("Option with label '" + this.label + "' not found");
3172
this.assertSelected = function(element) {
3173
var selectedLabel = element.options[element.selectedIndex].text;
3174
Assert.matches(this.label, selectedLabel)
3179
* OptionLocator for options identified by their values.
3181
OptionLocatorFactory.prototype.OptionLocatorByValue = function(value) {
3183
this.valueMatcher = new PatternMatcher(this.value);
3184
this.findOption = function(element) {
3185
for (var i = 0; i < element.options.length; i++) {
3186
if (this.valueMatcher.matches(element.options[i].value)) {
3187
return element.options[i];
3190
throw new SeleniumError("Option with value '" + this.value + "' not found");
3193
this.assertSelected = function(element) {
3194
var selectedValue = element.options[element.selectedIndex].value;
3195
Assert.matches(this.value, selectedValue)
3200
* OptionLocator for options identified by their index.
3202
OptionLocatorFactory.prototype.OptionLocatorByIndex = function(index) {
3203
this.index = Number(index);
3204
if (isNaN(this.index) || this.index < 0) {
3205
throw new SeleniumError("Illegal Index: " + index);
3208
this.findOption = function(element) {
3209
if (element.options.length <= this.index) {
3210
throw new SeleniumError("Index out of range. Only " + element.options.length + " options available");
3212
return element.options[this.index];
3215
this.assertSelected = function(element) {
3216
Assert.equals(this.index, element.selectedIndex);
3221
* OptionLocator for options identified by their id.
3223
OptionLocatorFactory.prototype.OptionLocatorById = function(id) {
3225
this.idMatcher = new PatternMatcher(this.id);
3226
this.findOption = function(element) {
3227
for (var i = 0; i < element.options.length; i++) {
3228
if (this.idMatcher.matches(element.options[i].id)) {
3229
return element.options[i];
3232
throw new SeleniumError("Option with id '" + this.id + "' not found");
3235
this.assertSelected = function(element) {
3236
var selectedId = element.options[element.selectedIndex].id;
3237
Assert.matches(this.id, selectedId)