PageRenderTime 27ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/testing/selenium-core/scripts/selenium-api.js

http://datanucleus-appengine.googlecode.com/
JavaScript | 3043 lines | 1457 code | 245 blank | 1341 comment | 286 complexity | 8e962db41a4337f77b196d02a4f6462d MD5 | raw file
Possible License(s): Apache-2.0
  1. /*
  2. * Copyright 2004 ThoughtWorks, Inc
  3. *
  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
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  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.
  15. *
  16. */
  17. // TODO: stop navigating this.browserbot.document() ... it breaks encapsulation
  18. var storedVars = new Object();
  19. function Selenium(browserbot) {
  20. /**
  21. * Defines an object that runs Selenium commands.
  22. *
  23. * <h3><a name="locators"></a>Element Locators</h3>
  24. * <p>
  25. * Element Locators tell Selenium which HTML element a command refers to.
  26. * The format of a locator is:</p>
  27. * <blockquote>
  28. * <em>locatorType</em><strong>=</strong><em>argument</em>
  29. * </blockquote>
  30. *
  31. * <p>
  32. * We support the following strategies for locating elements:
  33. * </p>
  34. *
  35. * <ul>
  36. * <li><strong>identifier</strong>=<em>id</em>:
  37. * Select the element with the specified &#064;id attribute. If no match is
  38. * found, select the first element whose &#064;name attribute is <em>id</em>.
  39. * (This is normally the default; see below.)</li>
  40. * <li><strong>id</strong>=<em>id</em>:
  41. * Select the element with the specified &#064;id attribute.</li>
  42. *
  43. * <li><strong>name</strong>=<em>name</em>:
  44. * Select the first element with the specified &#064;name attribute.
  45. * <ul class="first last simple">
  46. * <li>username</li>
  47. * <li>name=username</li>
  48. * </ul>
  49. *
  50. * <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>
  51. *
  52. * <ul class="first last simple">
  53. * <li>name=flavour value=chocolate</li>
  54. * </ul>
  55. * </li>
  56. * <li><strong>dom</strong>=<em>javascriptExpression</em>:
  57. *
  58. * Find an element by evaluating the specified string. This allows you to traverse the HTML Document Object
  59. * Model using JavaScript. Note that you must not return a value in this string; simply make it the last expression in the block.
  60. * <ul class="first last simple">
  61. * <li>dom=document.forms['myForm'].myDropdown</li>
  62. * <li>dom=document.images[56]</li>
  63. * <li>dom=function foo() { return document.links[1]; }; foo();</li>
  64. * </ul>
  65. *
  66. * </li>
  67. *
  68. * <li><strong>xpath</strong>=<em>xpathExpression</em>:
  69. * Locate an element using an XPath expression.
  70. * <ul class="first last simple">
  71. * <li>xpath=//img[&#064;alt='The image alt text']</li>
  72. * <li>xpath=//table[&#064;id='table1']//tr[4]/td[2]</li>
  73. * <li>xpath=//a[contains(&#064;href,'#id1')]</li>
  74. * <li>xpath=//a[contains(&#064;href,'#id1')]/&#064;class</li>
  75. * <li>xpath=(//table[&#064;class='stylee'])//th[text()='theHeaderText']/../td</li>
  76. * <li>xpath=//input[&#064;name='name2' and &#064;value='yes']</li>
  77. * <li>xpath=//*[text()="right"]</li>
  78. *
  79. * </ul>
  80. * </li>
  81. * <li><strong>link</strong>=<em>textPattern</em>:
  82. * Select the link (anchor) element which contains text matching the
  83. * specified <em>pattern</em>.
  84. * <ul class="first last simple">
  85. * <li>link=The link text</li>
  86. * </ul>
  87. *
  88. * </li>
  89. *
  90. * <li><strong>css</strong>=<em>cssSelectorSyntax</em>:
  91. * 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.
  92. * <ul class="first last simple">
  93. * <li>css=a[href="#id3"]</li>
  94. * <li>css=span#firstChild + span</li>
  95. * </ul>
  96. * <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>
  97. * </li>
  98. *
  99. * <li><strong>ui</strong>=<em>uiSpecifierString</em>:
  100. * 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.
  101. * <ul class="first last simple">
  102. * <li>ui=loginPages::loginButton()</li>
  103. * <li>ui=settingsPages::toggle(label=Hide Email)</li>
  104. * <li>ui=forumPages::postBody(index=2)//a[2]</li>
  105. * </ul>
  106. * </li>
  107. *
  108. * </ul>
  109. *
  110. * <p>
  111. * Without an explicit locator prefix, Selenium uses the following default
  112. * strategies:
  113. * </p>
  114. *
  115. * <ul class="simple">
  116. * <li><strong>dom</strong>, for locators starting with &quot;document.&quot;</li>
  117. * <li><strong>xpath</strong>, for locators starting with &quot;//&quot;</li>
  118. * <li><strong>identifier</strong>, otherwise</li>
  119. * </ul>
  120. *
  121. * <h3><a name="element-filters">Element Filters</a></h3>
  122. * <blockquote>
  123. * <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>
  124. * <p>Filters look much like locators, ie.</p>
  125. * <blockquote>
  126. * <em>filterType</em><strong>=</strong><em>argument</em></blockquote>
  127. *
  128. * <p>Supported element-filters are:</p>
  129. * <p><strong>value=</strong><em>valuePattern</em></p>
  130. * <blockquote>
  131. * Matches elements based on their values. This is particularly useful for refining a list of similarly-named toggle-buttons.</blockquote>
  132. * <p><strong>index=</strong><em>index</em></p>
  133. * <blockquote>
  134. * Selects a single element based on its position in the list (offset from zero).</blockquote>
  135. * </blockquote>
  136. *
  137. * <h3><a name="patterns"></a>String-match Patterns</h3>
  138. *
  139. * <p>
  140. * Various Pattern syntaxes are available for matching string values:
  141. * </p>
  142. * <ul>
  143. * <li><strong>glob:</strong><em>pattern</em>:
  144. * Match a string against a "glob" (aka "wildmat") pattern. "Glob" is a
  145. * kind of limited regular-expression syntax typically used in command-line
  146. * shells. In a glob pattern, "*" represents any sequence of characters, and "?"
  147. * represents any single character. Glob patterns match against the entire
  148. * string.</li>
  149. * <li><strong>regexp:</strong><em>regexp</em>:
  150. * Match a string using a regular-expression. The full power of JavaScript
  151. * regular-expressions is available.</li>
  152. * <li><strong>regexpi:</strong><em>regexpi</em>:
  153. * Match a string using a case-insensitive regular-expression.</li>
  154. * <li><strong>exact:</strong><em>string</em>:
  155. *
  156. * Match a string exactly, verbatim, without any of that fancy wildcard
  157. * stuff.</li>
  158. * </ul>
  159. * <p>
  160. * If no pattern prefix is specified, Selenium assumes that it's a "glob"
  161. * pattern.
  162. * </p>
  163. * <p>
  164. * For commands that return multiple values (such as verifySelectOptions),
  165. * the string being matched is a comma-separated list of the return values,
  166. * where both commas and backslashes in the values are backslash-escaped.
  167. * When providing a pattern, the optional matching syntax (i.e. glob,
  168. * regexp, etc.) is specified once, as usual, at the beginning of the
  169. * pattern.
  170. * </p>
  171. */
  172. this.browserbot = browserbot;
  173. this.optionLocatorFactory = new OptionLocatorFactory();
  174. // DGF for backwards compatibility
  175. this.page = function() {
  176. return browserbot;
  177. };
  178. this.defaultTimeout = Selenium.DEFAULT_TIMEOUT;
  179. this.mouseSpeed = 10;
  180. }
  181. Selenium.DEFAULT_TIMEOUT = 30 * 1000;
  182. Selenium.DEFAULT_MOUSE_SPEED = 10;
  183. Selenium.RIGHT_MOUSE_CLICK = 2;
  184. Selenium.decorateFunctionWithTimeout = function(f, timeout) {
  185. if (f == null) {
  186. return null;
  187. }
  188. var timeoutValue = parseInt(timeout);
  189. if (isNaN(timeoutValue)) {
  190. throw new SeleniumError("Timeout is not a number: '" + timeout + "'");
  191. }
  192. var now = new Date().getTime();
  193. var timeoutTime = now + timeoutValue;
  194. return function() {
  195. if (new Date().getTime() > timeoutTime) {
  196. throw new SeleniumError("Timed out after " + timeoutValue + "ms");
  197. }
  198. return f();
  199. };
  200. }
  201. Selenium.createForWindow = function(window, proxyInjectionMode) {
  202. if (!window.location) {
  203. throw "error: not a window!";
  204. }
  205. return new Selenium(BrowserBot.createForWindow(window, proxyInjectionMode));
  206. };
  207. Selenium.prototype.reset = function() {
  208. this.defaultTimeout = Selenium.DEFAULT_TIMEOUT;
  209. // todo: this.browserbot.reset()
  210. this.browserbot.selectWindow("null");
  211. this.browserbot.resetPopups();
  212. };
  213. Selenium.prototype.doClick = function(locator) {
  214. /**
  215. * Clicks on a link, button, checkbox or radio button. If the click action
  216. * causes a new page to load (like a link usually does), call
  217. * waitForPageToLoad.
  218. *
  219. * @param locator an element locator
  220. *
  221. */
  222. var element = this.browserbot.findElement(locator);
  223. this.browserbot.clickElement(element);
  224. };
  225. Selenium.prototype.doDoubleClick = function(locator) {
  226. /**
  227. * Double clicks on a link, button, checkbox or radio button. If the double click action
  228. * causes a new page to load (like a link usually does), call
  229. * waitForPageToLoad.
  230. *
  231. * @param locator an element locator
  232. *
  233. */
  234. var element = this.browserbot.findElement(locator);
  235. this.browserbot.doubleClickElement(element);
  236. };
  237. Selenium.prototype.doContextMenu = function(locator) {
  238. /**
  239. * Simulates opening the context menu for the specified element (as might happen if the user "right-clicked" on the element).
  240. *
  241. * @param locator an element locator
  242. *
  243. */
  244. var element = this.browserbot.findElement(locator);
  245. this.browserbot.contextMenuOnElement(element);
  246. };
  247. Selenium.prototype.doClickAt = function(locator, coordString) {
  248. /**
  249. * Clicks on a link, button, checkbox or radio button. If the click action
  250. * causes a new page to load (like a link usually does), call
  251. * waitForPageToLoad.
  252. *
  253. * @param locator an element locator
  254. * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
  255. * event relative to the element returned by the locator.
  256. *
  257. */
  258. var element = this.browserbot.findElement(locator);
  259. var clientXY = getClientXY(element, coordString)
  260. this.doMouseMove(locator);
  261. this.doMouseDown(locator);
  262. this.browserbot.clickElement(element, clientXY[0], clientXY[1]);
  263. this.doMouseUp(locator);
  264. };
  265. Selenium.prototype.doDoubleClickAt = function(locator, coordString) {
  266. /**
  267. * Doubleclicks on a link, button, checkbox or radio button. If the action
  268. * causes a new page to load (like a link usually does), call
  269. * waitForPageToLoad.
  270. *
  271. * @param locator an element locator
  272. * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
  273. * event relative to the element returned by the locator.
  274. *
  275. */
  276. var element = this.browserbot.findElement(locator);
  277. var clientXY = getClientXY(element, coordString)
  278. this.doMouseMove(locator);
  279. this.doMouseDown(locator);
  280. this.browserbot.doubleClickElement(element, clientXY[0], clientXY[1]);
  281. this.doMouseUp(locator);
  282. };
  283. Selenium.prototype.doContextMenuAt = function(locator, coordString) {
  284. /**
  285. * Simulates opening the context menu for the specified element (as might happen if the user "right-clicked" on the element).
  286. *
  287. * @param locator an element locator
  288. * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
  289. * event relative to the element returned by the locator.
  290. *
  291. */
  292. var element = this.browserbot.findElement(locator);
  293. var clientXY = getClientXY(element, coordString)
  294. this.browserbot.contextMenuOnElement(element, clientXY[0], clientXY[1]);
  295. };
  296. Selenium.prototype.doFireEvent = function(locator, eventName) {
  297. /**
  298. * Explicitly simulate an event, to trigger the corresponding &quot;on<em>event</em>&quot;
  299. * handler.
  300. *
  301. * @param locator an <a href="#locators">element locator</a>
  302. * @param eventName the event name, e.g. "focus" or "blur"
  303. */
  304. var element = this.browserbot.findElement(locator);
  305. triggerEvent(element, eventName, false);
  306. };
  307. Selenium.prototype.doFocus = function(locator) {
  308. /** Move the focus to the specified element; for example, if the element is an input field, move the cursor to that field.
  309. *
  310. * @param locator an <a href="#locators">element locator</a>
  311. */
  312. var element = this.browserbot.findElement(locator);
  313. if (element.focus) {
  314. element.focus();
  315. } else {
  316. triggerEvent(element, "focus", false);
  317. }
  318. }
  319. Selenium.prototype.doKeyPress = function(locator, keySequence) {
  320. /**
  321. * Simulates a user pressing and releasing a key.
  322. *
  323. * @param locator an <a href="#locators">element locator</a>
  324. * @param keySequence Either be a string("\" followed by the numeric keycode
  325. * of the key to be pressed, normally the ASCII value of that key), or a single
  326. * character. For example: "w", "\119".
  327. */
  328. var element = this.browserbot.findElement(locator);
  329. triggerKeyEvent(element, 'keypress', keySequence, true,
  330. this.browserbot.controlKeyDown,
  331. this.browserbot.altKeyDown,
  332. this.browserbot.shiftKeyDown,
  333. this.browserbot.metaKeyDown);
  334. };
  335. Selenium.prototype.doShiftKeyDown = function() {
  336. /**
  337. * Press the shift key and hold it down until doShiftUp() is called or a new page is loaded.
  338. *
  339. */
  340. this.browserbot.shiftKeyDown = true;
  341. };
  342. Selenium.prototype.doShiftKeyUp = function() {
  343. /**
  344. * Release the shift key.
  345. *
  346. */
  347. this.browserbot.shiftKeyDown = false;
  348. };
  349. Selenium.prototype.doMetaKeyDown = function() {
  350. /**
  351. * Press the meta key and hold it down until doMetaUp() is called or a new page is loaded.
  352. *
  353. */
  354. this.browserbot.metaKeyDown = true;
  355. };
  356. Selenium.prototype.doMetaKeyUp = function() {
  357. /**
  358. * Release the meta key.
  359. *
  360. */
  361. this.browserbot.metaKeyDown = false;
  362. };
  363. Selenium.prototype.doAltKeyDown = function() {
  364. /**
  365. * Press the alt key and hold it down until doAltUp() is called or a new page is loaded.
  366. *
  367. */
  368. this.browserbot.altKeyDown = true;
  369. };
  370. Selenium.prototype.doAltKeyUp = function() {
  371. /**
  372. * Release the alt key.
  373. *
  374. */
  375. this.browserbot.altKeyDown = false;
  376. };
  377. Selenium.prototype.doControlKeyDown = function() {
  378. /**
  379. * Press the control key and hold it down until doControlUp() is called or a new page is loaded.
  380. *
  381. */
  382. this.browserbot.controlKeyDown = true;
  383. };
  384. Selenium.prototype.doControlKeyUp = function() {
  385. /**
  386. * Release the control key.
  387. *
  388. */
  389. this.browserbot.controlKeyDown = false;
  390. };
  391. Selenium.prototype.doKeyDown = function(locator, keySequence) {
  392. /**
  393. * Simulates a user pressing a key (without releasing it yet).
  394. *
  395. * @param locator an <a href="#locators">element locator</a>
  396. * @param keySequence Either be a string("\" followed by the numeric keycode
  397. * of the key to be pressed, normally the ASCII value of that key), or a single
  398. * character. For example: "w", "\119".
  399. */
  400. var element = this.browserbot.findElement(locator);
  401. triggerKeyEvent(element, 'keydown', keySequence, true,
  402. this.browserbot.controlKeyDown,
  403. this.browserbot.altKeyDown,
  404. this.browserbot.shiftKeyDown,
  405. this.browserbot.metaKeyDown);
  406. };
  407. Selenium.prototype.doKeyUp = function(locator, keySequence) {
  408. /**
  409. * Simulates a user releasing a key.
  410. *
  411. * @param locator an <a href="#locators">element locator</a>
  412. * @param keySequence Either be a string("\" followed by the numeric keycode
  413. * of the key to be pressed, normally the ASCII value of that key), or a single
  414. * character. For example: "w", "\119".
  415. */
  416. var element = this.browserbot.findElement(locator);
  417. triggerKeyEvent(element, 'keyup', keySequence, true,
  418. this.browserbot.controlKeyDown,
  419. this.browserbot.altKeyDown,
  420. this.browserbot.shiftKeyDown,
  421. this.browserbot.metaKeyDown);
  422. };
  423. function getClientXY(element, coordString) {
  424. // Parse coordString
  425. var coords = null;
  426. var x;
  427. var y;
  428. if (coordString) {
  429. coords = coordString.split(/,/);
  430. x = Number(coords[0]);
  431. y = Number(coords[1]);
  432. }
  433. else {
  434. x = y = 0;
  435. }
  436. // Get position of element,
  437. // Return 2 item array with clientX and clientY
  438. return [Selenium.prototype.getElementPositionLeft(element) + x, Selenium.prototype.getElementPositionTop(element) + y];
  439. }
  440. Selenium.prototype.doMouseOver = function(locator) {
  441. /**
  442. * Simulates a user hovering a mouse over the specified element.
  443. *
  444. * @param locator an <a href="#locators">element locator</a>
  445. */
  446. var element = this.browserbot.findElement(locator);
  447. this.browserbot.triggerMouseEvent(element, 'mouseover', true);
  448. };
  449. Selenium.prototype.doMouseOut = function(locator) {
  450. /**
  451. * Simulates a user moving the mouse pointer away from the specified element.
  452. *
  453. * @param locator an <a href="#locators">element locator</a>
  454. */
  455. var element = this.browserbot.findElement(locator);
  456. this.browserbot.triggerMouseEvent(element, 'mouseout', true);
  457. };
  458. Selenium.prototype.doMouseDown = function(locator) {
  459. /**
  460. * Simulates a user pressing the left mouse button (without releasing it yet) on
  461. * the specified element.
  462. *
  463. * @param locator an <a href="#locators">element locator</a>
  464. */
  465. var element = this.browserbot.findElement(locator);
  466. this.browserbot.triggerMouseEvent(element, 'mousedown', true);
  467. };
  468. Selenium.prototype.doMouseDownRight = function(locator) {
  469. /**
  470. * Simulates a user pressing the right mouse button (without releasing it yet) on
  471. * the specified element.
  472. *
  473. * @param locator an <a href="#locators">element locator</a>
  474. */
  475. var element = this.browserbot.findElement(locator);
  476. this.browserbot.triggerMouseEvent(element, 'mousedown', true, undefined, undefined, Selenium.RIGHT_MOUSE_CLICK);
  477. };
  478. Selenium.prototype.doMouseDownAt = function(locator, coordString) {
  479. /**
  480. * Simulates a user pressing the left mouse button (without releasing it yet) at
  481. * the specified location.
  482. *
  483. * @param locator an <a href="#locators">element locator</a>
  484. * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
  485. * event relative to the element returned by the locator.
  486. */
  487. var element = this.browserbot.findElement(locator);
  488. var clientXY = getClientXY(element, coordString)
  489. this.browserbot.triggerMouseEvent(element, 'mousedown', true, clientXY[0], clientXY[1]);
  490. };
  491. Selenium.prototype.doMouseDownRightAt = function(locator, coordString) {
  492. /**
  493. * Simulates a user pressing the right mouse button (without releasing it yet) at
  494. * the specified location.
  495. *
  496. * @param locator an <a href="#locators">element locator</a>
  497. * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
  498. * event relative to the element returned by the locator.
  499. */
  500. var element = this.browserbot.findElement(locator);
  501. var clientXY = getClientXY(element, coordString)
  502. this.browserbot.triggerMouseEvent(element, 'mousedown', true, clientXY[0], clientXY[1], Selenium.RIGHT_MOUSE_CLICK);
  503. };
  504. Selenium.prototype.doMouseUp = function(locator) {
  505. /**
  506. * Simulates the event that occurs when the user releases the mouse button (i.e., stops
  507. * holding the button down) on the specified element.
  508. *
  509. * @param locator an <a href="#locators">element locator</a>
  510. */
  511. var element = this.browserbot.findElement(locator);
  512. this.browserbot.triggerMouseEvent(element, 'mouseup', true);
  513. };
  514. Selenium.prototype.doMouseUpRight = function(locator) {
  515. /**
  516. * Simulates the event that occurs when the user releases the right mouse button (i.e., stops
  517. * holding the button down) on the specified element.
  518. *
  519. * @param locator an <a href="#locators">element locator</a>
  520. */
  521. var element = this.browserbot.findElement(locator);
  522. this.browserbot.triggerMouseEvent(element, 'mouseup', true, undefined, undefined, Selenium.RIGHT_MOUSE_CLICK);
  523. };
  524. Selenium.prototype.doMouseUpAt = function(locator, coordString) {
  525. /**
  526. * Simulates the event that occurs when the user releases the mouse button (i.e., stops
  527. * holding the button down) at the specified location.
  528. *
  529. * @param locator an <a href="#locators">element locator</a>
  530. * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
  531. * event relative to the element returned by the locator.
  532. */
  533. var element = this.browserbot.findElement(locator);
  534. var clientXY = getClientXY(element, coordString)
  535. this.browserbot.triggerMouseEvent(element, 'mouseup', true, clientXY[0], clientXY[1]);
  536. };
  537. Selenium.prototype.doMouseUpRightAt = function(locator, coordString) {
  538. /**
  539. * Simulates the event that occurs when the user releases the right mouse button (i.e., stops
  540. * holding the button down) at the specified location.
  541. *
  542. * @param locator an <a href="#locators">element locator</a>
  543. * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
  544. * event relative to the element returned by the locator.
  545. */
  546. var element = this.browserbot.findElement(locator);
  547. var clientXY = getClientXY(element, coordString)
  548. this.browserbot.triggerMouseEvent(element, 'mouseup', true, clientXY[0], clientXY[1], Selenium.RIGHT_MOUSE_CLICK);
  549. };
  550. Selenium.prototype.doMouseMove = function(locator) {
  551. /**
  552. * Simulates a user pressing the mouse button (without releasing it yet) on
  553. * the specified element.
  554. *
  555. * @param locator an <a href="#locators">element locator</a>
  556. */
  557. var element = this.browserbot.findElement(locator);
  558. this.browserbot.triggerMouseEvent(element, 'mousemove', true);
  559. };
  560. Selenium.prototype.doMouseMoveAt = function(locator, coordString) {
  561. /**
  562. * Simulates a user pressing the mouse button (without releasing it yet) on
  563. * the specified element.
  564. *
  565. * @param locator an <a href="#locators">element locator</a>
  566. * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse
  567. * event relative to the element returned by the locator.
  568. */
  569. var element = this.browserbot.findElement(locator);
  570. var clientXY = getClientXY(element, coordString)
  571. this.browserbot.triggerMouseEvent(element, 'mousemove', true, clientXY[0], clientXY[1]);
  572. };
  573. Selenium.prototype.doType = function(locator, value) {
  574. /**
  575. * Sets the value of an input field, as though you typed it in.
  576. *
  577. * <p>Can also be used to set the value of combo boxes, check boxes, etc. In these cases,
  578. * value should be the value of the option selected, not the visible text.</p>
  579. *
  580. * @param locator an <a href="#locators">element locator</a>
  581. * @param value the value to type
  582. */
  583. if (this.browserbot.controlKeyDown || this.browserbot.altKeyDown || this.browserbot.metaKeyDown) {
  584. throw new SeleniumError("type not supported immediately after call to controlKeyDown() or altKeyDown() or metaKeyDown()");
  585. }
  586. // TODO fail if it can't be typed into.
  587. var element = this.browserbot.findElement(locator);
  588. if (this.browserbot.shiftKeyDown) {
  589. value = new String(value).toUpperCase();
  590. }
  591. this.browserbot.replaceText(element, value);
  592. };
  593. Selenium.prototype.doTypeKeys = function(locator, value) {
  594. /**
  595. * Simulates keystroke events on the specified element, as though you typed the value key-by-key.
  596. *
  597. * <p>This is a convenience method for calling keyDown, keyUp, keyPress for every character in the specified string;
  598. * this is useful for dynamic UI widgets (like auto-completing combo boxes) that require explicit key events.</p>
  599. *
  600. * <p>Unlike the simple "type" command, which forces the specified value into the page directly, this command
  601. * may or may not have any visible effect, even in cases where typing keys would normally have a visible effect.
  602. * For example, if you use "typeKeys" on a form element, you may or may not see the results of what you typed in
  603. * the field.</p>
  604. * <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
  605. * send the keystroke events corresponding to what you just typed.</p>
  606. *
  607. * @param locator an <a href="#locators">element locator</a>
  608. * @param value the value to type
  609. */
  610. var keys = new String(value).split("");
  611. for (var i = 0; i < keys.length; i++) {
  612. var c = keys[i];
  613. this.doKeyDown(locator, c);
  614. this.doKeyUp(locator, c);
  615. this.doKeyPress(locator, c);
  616. }
  617. };
  618. Selenium.prototype.doSetSpeed = function(value) {
  619. /**
  620. * 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.,
  621. * the delay is 0 milliseconds.
  622. *
  623. * @param value the number of milliseconds to pause after operation
  624. */
  625. throw new SeleniumError("this operation is only implemented in selenium-rc, and should never result in a request making it across the wire");
  626. };
  627. Selenium.prototype.getSpeed = function() {
  628. /**
  629. * 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.,
  630. * the delay is 0 milliseconds.
  631. *
  632. * See also setSpeed.
  633. *
  634. * @return string the execution speed in milliseconds.
  635. */
  636. throw new SeleniumError("this operation is only implemented in selenium-rc, and should never result in a request making it across the wire");
  637. };
  638. Selenium.prototype.findToggleButton = function(locator) {
  639. var element = this.browserbot.findElement(locator);
  640. if (element.checked == null) {
  641. Assert.fail("Element " + locator + " is not a toggle-button.");
  642. }
  643. return element;
  644. }
  645. Selenium.prototype.doCheck = function(locator) {
  646. /**
  647. * Check a toggle-button (checkbox/radio)
  648. *
  649. * @param locator an <a href="#locators">element locator</a>
  650. */
  651. this.findToggleButton(locator).checked = true;
  652. };
  653. Selenium.prototype.doUncheck = function(locator) {
  654. /**
  655. * Uncheck a toggle-button (checkbox/radio)
  656. *
  657. * @param locator an <a href="#locators">element locator</a>
  658. */
  659. this.findToggleButton(locator).checked = false;
  660. };
  661. Selenium.prototype.doSelect = function(selectLocator, optionLocator) {
  662. /**
  663. * Select an option from a drop-down using an option locator.
  664. *
  665. * <p>
  666. * Option locators provide different ways of specifying options of an HTML
  667. * Select element (e.g. for selecting a specific option, or for asserting
  668. * that the selected option satisfies a specification). There are several
  669. * forms of Select Option Locator.
  670. * </p>
  671. * <ul>
  672. * <li><strong>label</strong>=<em>labelPattern</em>:
  673. * matches options based on their labels, i.e. the visible text. (This
  674. * is the default.)
  675. * <ul class="first last simple">
  676. * <li>label=regexp:^[Oo]ther</li>
  677. * </ul>
  678. * </li>
  679. * <li><strong>value</strong>=<em>valuePattern</em>:
  680. * matches options based on their values.
  681. * <ul class="first last simple">
  682. * <li>value=other</li>
  683. * </ul>
  684. *
  685. *
  686. * </li>
  687. * <li><strong>id</strong>=<em>id</em>:
  688. *
  689. * matches options based on their ids.
  690. * <ul class="first last simple">
  691. * <li>id=option1</li>
  692. * </ul>
  693. * </li>
  694. * <li><strong>index</strong>=<em>index</em>:
  695. * matches an option based on its index (offset from zero).
  696. * <ul class="first last simple">
  697. *
  698. * <li>index=2</li>
  699. * </ul>
  700. * </li>
  701. * </ul>
  702. * <p>
  703. * If no option locator prefix is provided, the default behaviour is to match on <strong>label</strong>.
  704. * </p>
  705. *
  706. *
  707. * @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
  708. * @param optionLocator an option locator (a label by default)
  709. */
  710. var element = this.browserbot.findElement(selectLocator);
  711. if (!("options" in element)) {
  712. throw new SeleniumError("Specified element is not a Select (has no options)");
  713. }
  714. var locator = this.optionLocatorFactory.fromLocatorString(optionLocator);
  715. var option = locator.findOption(element);
  716. this.browserbot.selectOption(element, option);
  717. };
  718. Selenium.prototype.doAddSelection = function(locator, optionLocator) {
  719. /**
  720. * Add a selection to the set of selected options in a multi-select element using an option locator.
  721. *
  722. * @see #doSelect for details of option locators
  723. *
  724. * @param locator an <a href="#locators">element locator</a> identifying a multi-select box
  725. * @param optionLocator an option locator (a label by default)
  726. */
  727. var element = this.browserbot.findElement(locator);
  728. if (!("options" in element)) {
  729. throw new SeleniumError("Specified element is not a Select (has no options)");
  730. }
  731. var locator = this.optionLocatorFactory.fromLocatorString(optionLocator);
  732. var option = locator.findOption(element);
  733. this.browserbot.addSelection(element, option);
  734. };
  735. Selenium.prototype.doRemoveSelection = function(locator, optionLocator) {
  736. /**
  737. * Remove a selection from the set of selected options in a multi-select element using an option locator.
  738. *
  739. * @see #doSelect for details of option locators
  740. *
  741. * @param locator an <a href="#locators">element locator</a> identifying a multi-select box
  742. * @param optionLocator an option locator (a label by default)
  743. */
  744. var element = this.browserbot.findElement(locator);
  745. if (!("options" in element)) {
  746. throw new SeleniumError("Specified element is not a Select (has no options)");
  747. }
  748. var locator = this.optionLocatorFactory.fromLocatorString(optionLocator);
  749. var option = locator.findOption(element);
  750. this.browserbot.removeSelection(element, option);
  751. };
  752. Selenium.prototype.doRemoveAllSelections = function(locator) {
  753. /**
  754. * Unselects all of the selected options in a multi-select element.
  755. *
  756. * @param locator an <a href="#locators">element locator</a> identifying a multi-select box
  757. */
  758. var element = this.browserbot.findElement(locator);
  759. if (!("options" in element)) {
  760. throw new SeleniumError("Specified element is not a Select (has no options)");
  761. }
  762. for (var i = 0; i < element.options.length; i++) {
  763. this.browserbot.removeSelection(element, element.options[i]);
  764. }
  765. }
  766. Selenium.prototype.doSubmit = function(formLocator) {
  767. /**
  768. * Submit the specified form. This is particularly useful for forms without
  769. * submit buttons, e.g. single-input "Search" forms.
  770. *
  771. * @param formLocator an <a href="#locators">element locator</a> for the form you want to submit
  772. */
  773. var form = this.browserbot.findElement(formLocator);
  774. return this.browserbot.submit(form);
  775. };
  776. Selenium.prototype.makePageLoadCondition = function(timeout) {
  777. if (timeout == null) {
  778. timeout = this.defaultTimeout;
  779. }
  780. // if the timeout is zero, we won't wait for the page to load before returning
  781. if (timeout == 0) {
  782. return;
  783. }
  784. return Selenium.decorateFunctionWithTimeout(fnBind(this._isNewPageLoaded, this), timeout);
  785. };
  786. Selenium.prototype.doOpen = function(url) {
  787. /**
  788. * Opens an URL in the test frame. This accepts both relative and absolute
  789. * URLs.
  790. *
  791. * The &quot;open&quot; command waits for the page to load before proceeding,
  792. * ie. the &quot;AndWait&quot; suffix is implicit.
  793. *
  794. * <em>Note</em>: The URL must be on the same domain as the runner HTML
  795. * due to security restrictions in the browser (Same Origin Policy). If you
  796. * need to open an URL on another domain, use the Selenium Server to start a
  797. * new browser session on that domain.
  798. *
  799. * @param url the URL to open; may be relative or absolute
  800. */
  801. this.browserbot.openLocation(url);
  802. if (window["proxyInjectionMode"] == null || !window["proxyInjectionMode"]) {
  803. return this.makePageLoadCondition();
  804. } // in PI mode, just return "OK"; the server will waitForLoad
  805. };
  806. Selenium.prototype.doOpenWindow = function(url, windowID) {
  807. /**
  808. * Opens a popup window (if a window with that ID isn't already open).
  809. * After opening the window, you'll need to select it using the selectWindow
  810. * command.
  811. *
  812. * <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).
  813. * In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using
  814. * an empty (blank) url, like this: openWindow("", "myFunnyWindow").</p>
  815. *
  816. * @param url the URL to open, which can be blank
  817. * @param windowID the JavaScript window ID of the window to select
  818. */
  819. this.browserbot.openWindow(url, windowID);
  820. };
  821. Selenium.prototype.doSelectWindow = function(windowID) {
  822. /**
  823. * Selects a popup window using a window locator; once a popup window has been selected, all
  824. * commands go to that window. To select the main window again, use null
  825. * as the target.
  826. *
  827. * <p>
  828. *
  829. * Window locators provide different ways of specifying the window object:
  830. * by title, by internal JavaScript "name," or by JavaScript variable.
  831. * </p>
  832. * <ul>
  833. * <li><strong>title</strong>=<em>My Special Window</em>:
  834. * Finds the window using the text that appears in the title bar. Be careful;
  835. * two windows can share the same title. If that happens, this locator will
  836. * just pick one.
  837. * </li>
  838. * <li><strong>name</strong>=<em>myWindow</em>:
  839. * Finds the window using its internal JavaScript "name" property. This is the second
  840. * parameter "windowName" passed to the JavaScript method window.open(url, windowName, windowFeatures, replaceFlag)
  841. * (which Selenium intercepts).
  842. * </li>
  843. * <li><strong>var</strong>=<em>variableName</em>:
  844. * Some pop-up windows are unnamed (anonymous), but are associated with a JavaScript variable name in the current
  845. * application window, e.g. "window.foo = window.open(url);". In those cases, you can open the window using
  846. * "var=foo".
  847. * </li>
  848. * </ul>
  849. * <p>
  850. * If no window locator prefix is provided, we'll try to guess what you mean like this:</p>
  851. * <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>
  852. * <p>2.) if the value of the "windowID" parameter is a JavaScript variable name in the current application window, then it is assumed
  853. * that this variable contains the return value from a call to the JavaScript window.open() method.</p>
  854. * <p>3.) Otherwise, selenium looks in a hash it maintains that maps string names to window "names".</p>
  855. * <p>4.) If <em>that</em> fails, we'll try looping over all of the known windows to try to find the appropriate "title".
  856. * Since "title" is not necessarily unique, this may have unexpected behavior.</p>
  857. *
  858. * <p>If you're having trouble figuring out the name of a window that you want to manipulate, look at the Selenium log messages
  859. * which identify the names of windows created via window.open (and therefore intercepted by Selenium). You will see messages
  860. * like the following for each window as it is opened:</p>
  861. *
  862. * <p><code>debug: window.open call intercepted; window ID (which you can use with selectWindow()) is "myNewWindow"</code></p>
  863. *
  864. * <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).
  865. * (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
  866. * an empty (blank) url, like this: openWindow("", "myFunnyWindow").</p>
  867. *
  868. * @param windowID the JavaScript window ID of the window to select
  869. */
  870. this.browserbot.selectWindow(windowID);
  871. };
  872. Selenium.prototype.doSelectFrame = function(locator) {
  873. /**
  874. * Selects a frame within the current window. (You may invoke this command
  875. * multiple times to select nested frames.) To select the parent frame, use
  876. * "relative=parent" as a locator; to select the top frame, use "relative=top".
  877. * You can also select a frame by its 0-based index number; select the first frame with
  878. * "index=0", or the third frame with "index=2".
  879. *
  880. * <p>You may also use a DOM expression to identify the frame you want directly,
  881. * like this: <code>dom=frames["main"].frames["subframe"]</code></p>
  882. *
  883. * @param locator an <a href="#locators">element locator</a> identifying a frame or iframe
  884. */
  885. this.browserbot.selectFrame(locator);
  886. };
  887. Selenium.prototype.getWhetherThisFrameMatchFrameExpression = function(currentFrameString, target) {
  888. /**
  889. * Determine whether current/locator identify the frame containing this running code.
  890. *
  891. * <p>This is useful in proxy injection mode, where this code runs in every
  892. * browser frame and window, and sometimes the selenium server needs to identify
  893. * the "current" frame. In this case, when the test calls selectFrame, this
  894. * routine is called for each frame to figure out which one has been selected.
  895. * The selected frame will return true, while all others will return false.</p>
  896. *
  897. * @param currentFrameString starting frame
  898. * @param target new frame (which might be relative to the current one)
  899. * @return boolean true if the new frame is this code's window
  900. */
  901. return this.browserbot.doesThisFrameMatchFrameExpression(currentFrameString, target);
  902. };
  903. Selenium.prototype.getWhetherThisWindowMatchWindowExpression = function(currentWindowString, target) {
  904. /**
  905. * Determine whether currentWindowString plus target identify the window containing this running code.
  906. *
  907. * <p>This is useful in proxy injection mode, where this code runs in every
  908. * browser frame and window, and sometimes the selenium server needs to identify
  909. * the "current" window. In this case, when the test calls selectWindow, this
  910. * routine is called for each window to figure out which one has been selected.
  911. * The selected window will return true, while all others will return false.</p>
  912. *
  913. * @param currentWindowString starting window
  914. * @param target new window (which might be relative to the current one, e.g., "_parent")
  915. * @return boolean true if the new window is this code's window
  916. */
  917. if (window.opener!=null && window.opener[target]!=null && window.opener[target]==window) {
  918. return true;
  919. }
  920. return false;
  921. };
  922. Selenium.prototype.doWaitForPopUp = function(windowID, timeout) {
  923. /**
  924. * Waits for a popup window to appear and load up.
  925. *
  926. * @param windowID the JavaScript window "name" of the window that will appear (not the text of the title bar)
  927. * @param timeout a timeout in milliseconds, after which the action will return with an error
  928. */
  929. var popupLoadedPredicate = function () {
  930. var targetWindow = selenium.browserbot.getWindowByName(windowID, true);
  931. if (!targetWindow) return false;
  932. if (!targetWindow.location) return false;
  933. if ("about:blank" == targetWindow.location) return false;
  934. if (browserVersion.isKonqueror) {
  935. if ("/" == targetWindow.location.href) {
  936. // apparently Konqueror uses this as the temporary location, instead of about:blank
  937. return false;
  938. }
  939. }
  940. if (browserVersion.isSafari) {
  941. if(targetWindow.location.href == selenium.browserbot.buttonWindow.location.href) {
  942. // Apparently Safari uses this as the temporary location, instead of about:blank
  943. // what a world!
  944. LOG.debug("DGF what a world!");
  945. return false;
  946. }
  947. }
  948. if (!targetWindow.document) return false;
  949. if (!selenium.browserbot.getCurrentWindow().document.readyState) {
  950. // This is Firefox, with no readyState extension
  951. return true;
  952. }
  953. if ('complete' != targetWindow.document.readyState) return false;
  954. return true;
  955. };
  956. return Selenium.decorateFunctionWithTimeout(popupLoadedPredicate, timeout);
  957. }
  958. Selenium.prototype.doWaitForPopUp.dontCheckAlertsAndConfirms = true;
  959. Selenium.prototype.doChooseCancelOnNextConfirmation = function() {
  960. /**
  961. * <p>
  962. * By default, Selenium's overridden window.confirm() function will
  963. * return true, as if the user had manually clicked OK; after running
  964. * this command, the next call to confirm() will return false, as if
  965. * the user had clicked Cancel. Selenium will then resume using the
  966. * default behavior for future confirmations, automatically returning
  967. * true (OK) unless/until you explicitly call this command for each
  968. * confirmation.
  969. * </p>
  970. * <p>
  971. * Take note - every time a confirmation comes up, you must
  972. * consume it with a corresponding getConfirmation, or else
  973. * the next selenium operation will fail.
  974. * </p>
  975. */
  976. this.browserbot.cancelNextConfirmation(false);
  977. };
  978. Selenium.prototype.doChooseOkOnNextConfirmation = function() {
  979. /**
  980. * <p>
  981. * Undo the effect of calling chooseCancelOnNextConfirmation. Note
  982. * that Selenium's overridden window.confirm() function will normally automatically
  983. * return true, as if the user had manually clicked OK, so you shouldn't
  984. * need to use this command unless for some reason you need to change
  985. * your mind prior to the next confirmation. After any confirmation, Selenium will resume using the
  986. * default behavior for future confirmations, automatically returning
  987. * true (OK) unless/until you explicitly call chooseCancelOnNextConfirmation for each
  988. * confirmation.
  989. * </p>
  990. * <p>
  991. * Take note - every time a confirmation comes up, you must
  992. * consume it with a corresponding getConfirmation, or else
  993. * the next selenium operation will fail.
  994. * </p>
  995. *
  996. */
  997. this.browserbot.cancelNextConfirmation(true);
  998. };
  999. Selenium.prototype.doAnswerOnNextPrompt = function(answer) {
  1000. /**
  1001. * Instructs Selenium to return the specified answer string in response to
  1002. * the next JavaScript prompt [window.prompt()].
  1003. *
  1004. *
  1005. * @param answer the answer to give in response to the prompt pop-up
  1006. */
  1007. this.browserbot.setNextPromptResult(answer);
  1008. };
  1009. Selenium.prototype.doGoBack = function() {
  1010. /**
  1011. * Simulates the user clicking the "back" button on their browser.
  1012. *
  1013. */
  1014. this.browserbot.goBack();
  1015. };
  1016. Selenium.prototype.doRefresh = function() {
  1017. /**
  1018. * Simulates the user clicking the "Refresh" button on their browser.
  1019. *
  1020. */
  1021. this.browserbot.refresh();
  1022. };
  1023. Selenium.prototype.doClose = function() {
  1024. /**
  1025. * Simulates the user clicking the "close" button in the titlebar of a popup
  1026. * window or tab.
  1027. */
  1028. this.browserbot.close();
  1029. };
  1030. Selenium.prototype.ensureNoUnhandledPopups = function() {
  1031. if (this.browserbot.hasAlerts()) {
  1032. throw new SeleniumError("There was an unexpected Alert! [" + this.browserbot.getNextAlert() + "]");
  1033. }
  1034. if ( this.browserbot.hasConfirmations() ) {
  1035. throw new SeleniumError("There was an unexpected Confirmation! [" + this.browserbot.getNextConfirmation() + "]");
  1036. }
  1037. };
  1038. Selenium.prototype.isAlertPresent = function() {
  1039. /**
  1040. * Has an alert occurred?
  1041. *
  1042. * <p>
  1043. * This function never throws an exception
  1044. * </p>
  1045. * @return boolean true if there is an alert
  1046. */
  1047. return this.browserbot.hasAlerts();
  1048. };
  1049. Selenium.prototype.isPromptPresent = function() {
  1050. /**
  1051. * Has a prompt occurred?
  1052. *
  1053. * <p>
  1054. * This function never throws an exception
  1055. * </p>
  1056. * @return boolean true if there is a pending prompt
  1057. */
  1058. return this.browserbot.hasPrompts();
  1059. };
  1060. Selenium.prototype.isConfirmationPresent = function() {
  1061. /**
  1062. * Has confirm() been called?
  1063. *
  1064. * <p>
  1065. * This function never throws an exception
  1066. * </p>
  1067. * @return boolean true if there is a pending confirmation
  1068. */
  1069. return this.browserbot.hasConfirmations();
  1070. };
  1071. Selenium.prototype.getAlert = function() {
  1072. /**
  1073. * Retrieves the message of a JavaScript alert generated during the previous action, or fail if there were no alerts.
  1074. *
  1075. * <p>Getting an alert has the same effect as manually clicking OK. If an
  1076. * alert is generated but you do not consume it with getAlert, the next Selenium action
  1077. * will fail.</p>
  1078. *
  1079. * <p>Under Selenium, JavaScript alerts will NOT pop up a visible alert
  1080. * dialog.</p>
  1081. *
  1082. * <p>Selenium does NOT support JavaScript alerts that are generated in a
  1083. * page's onload() event handler. In this case a visible dialog WILL be
  1084. * generated and Selenium will hang until someone manually clicks OK.</p>
  1085. * @return string The message of the most recent JavaScript alert
  1086. */
  1087. if (!this.browserbot.hasAlerts()) {
  1088. Assert.fail("There were no alerts");
  1089. }
  1090. return this.browserbot.getNextAlert();
  1091. };
  1092. Selenium.prototype.getAlert.dontCheckAlertsAndConfirms = true;
  1093. Selenium.prototype.getConfirmation = function() {
  1094. /**
  1095. * Retrieves the message of a JavaScript confirmation dialog generated during
  1096. * the previous action.
  1097. *
  1098. * <p>
  1099. * By default, the confirm function will return true, having the same effect
  1100. * as manually clicking OK. This can be changed by prior execution of the
  1101. * chooseCancelOnNextConfirmation command.
  1102. * </p>
  1103. * <p>
  1104. * If an confirmation is generated but you do not consume it with getConfirmation,
  1105. * the next Selenium action will fail.
  1106. * </p>
  1107. *
  1108. * <p>
  1109. * NOTE: under Selenium, JavaScript confirmations will NOT pop up a visible
  1110. * dialog.
  1111. * </p>
  1112. *
  1113. * <p>
  1114. * NOTE: Selenium does NOT support JavaScript confirmations that are
  1115. * generated in a page's onload() event handler. In this case a visible
  1116. * dialog WILL be generated and Selenium will hang until you manually click
  1117. * OK.
  1118. * </p>
  1119. *
  1120. * @return string the message of the most recent JavaScript confirmation dialog
  1121. */
  1122. if (!this.browserbot.hasConfirmations()) {
  1123. Assert.fail("There were no confirmations");
  1124. }
  1125. return this.browserbot.getNextConfirmation();
  1126. };
  1127. Selenium.prototype.getConfirmation.dontCheckAlertsAndConfirms = true;
  1128. Selenium.prototype.getPrompt = function() {
  1129. /**
  1130. * Retrieves the message of a JavaScript question prompt dialog generated during
  1131. * the previous action.
  1132. *
  1133. * <p>Successful handling of the prompt requires prior execution of the
  1134. * answerOnNextPrompt command. If a prompt is generated but you
  1135. * do not get/verify it, the next Selenium action will fail.</p>
  1136. *
  1137. * <p>NOTE: under Selenium, JavaScript prompts will NOT pop up a visible
  1138. * dialog.</p>
  1139. *
  1140. * <p>NOTE: Selenium does NOT support JavaScript prompts that are generated in a
  1141. * page's onload() event handler. In this case a visible dialog WILL be
  1142. * generated and Selenium will hang until someone manually clicks OK.</p>
  1143. * @return string the message of the most recent JavaScript question prompt
  1144. */
  1145. if (! this.browserbot.hasPrompts()) {
  1146. Assert.fail("There were no prompts");
  1147. }
  1148. return this.browserbot.getNextPrompt();
  1149. };
  1150. Selenium.prototype.getLocation = function() {
  1151. /** Gets the absolute URL of the current page.
  1152. *
  1153. * @return string the absolute URL of the current page
  1154. */
  1155. return this.browserbot.getCurrentWindow().location.href;
  1156. };
  1157. Selenium.prototype.getTitle = function() {
  1158. /** Gets the title of the current page.
  1159. *
  1160. * @return string the title of the current page
  1161. */
  1162. return this.browserbot.getTitle();
  1163. };
  1164. Selenium.prototype.getBodyText = function() {
  1165. /**
  1166. * Gets the entire text of the page.
  1167. * @return string the entire text of the page
  1168. */
  1169. return this.browserbot.bodyText();
  1170. };
  1171. Selenium.prototype.getValue = function(locator) {
  1172. /**
  1173. * Gets the (whitespace-trimmed) value of an input field (or anything else with a value parameter).
  1174. * For checkbox/radio elements, the value will be "on" or "off" depending on
  1175. * whether the element is checked or not.
  1176. *
  1177. * @param locator an <a href="#locators">element locator</a>
  1178. * @return string the element value, or "on/off" for checkbox/radio elements
  1179. */
  1180. var element = this.browserbot.findElement(locator)
  1181. return getInputValue(element).trim();
  1182. }
  1183. Selenium.prototype.getText = function(locator) {
  1184. /**
  1185. * Gets the text of an element. This works for any element that contains
  1186. * text. This command uses either the textContent (Mozilla-like browsers) or
  1187. * the innerText (IE-like browsers) of the element, which is the rendered
  1188. * text shown to the user.
  1189. *
  1190. * @param locator an <a href="#locators">element locator</a>
  1191. * @return string the text of the element
  1192. */
  1193. var element = this.browserbot.findElement(locator);
  1194. return getText(element).trim();
  1195. };
  1196. Selenium.prototype.doHighlight = function(locator) {
  1197. /**
  1198. * Briefly changes the backgroundColor of the specified element yellow. Useful for debugging.
  1199. *
  1200. * @param locator an <a href="#locators">element locator</a>
  1201. */
  1202. var element = this.browserbot.findElement(locator);
  1203. this.browserbot.highlight(element, true);
  1204. };
  1205. Selenium.prototype.getEval = function(script) {
  1206. /** Gets the result of evaluating the specified JavaScript snippet. The snippet may
  1207. * have multiple lines, but only the result of the last line will be returned.
  1208. *
  1209. * <p>Note that, by default, the snippet will run in the context of the "selenium"
  1210. * object itself, so <code>this</code> will refer to the Selenium object. Use <code>window</code> to
  1211. * refer to the window of your application, e.g. <code>window.document.getElementById('foo')</code></p>
  1212. *
  1213. * <p>If you need to use
  1214. * a locator to refer to a single element in your application page, you can
  1215. * use <code>this.browserbot.findElement("id=foo")</code> where "id=foo" is your locator.</p>
  1216. *
  1217. * @param script the JavaScript snippet to run
  1218. * @return string the results of evaluating the snippet
  1219. */
  1220. try {
  1221. var window = this.browserbot.getCurrentWindow();
  1222. var result = eval(script);
  1223. // Selenium RC doesn't allow returning null
  1224. if (null == result) return "null";
  1225. return result;
  1226. } catch (e) {
  1227. throw new SeleniumError("Threw an exception: " + extractExceptionMessage(e));
  1228. }
  1229. };
  1230. Selenium.prototype.isChecked = function(locator) {
  1231. /**
  1232. * Gets whether a toggle-button (checkbox/radio) is checked. Fails if the specified element doesn't exist or isn't a toggle-button.
  1233. * @param locator an <a href="#locators">element locator</a> pointing to a checkbox or radio button
  1234. * @return boolean true if the checkbox is checked, false otherwise
  1235. */
  1236. var element = this.browserbot.findElement(locator);
  1237. if (element.checked == null) {
  1238. throw new SeleniumError("Element " + locator + " is not a toggle-button.");
  1239. }
  1240. return element.checked;
  1241. };
  1242. Selenium.prototype.getTable = function(tableCellAddress) {
  1243. /**
  1244. * Gets the text from a cell of a table. The cellAddress syntax
  1245. * tableLocator.row.column, where row and column start at 0.
  1246. *
  1247. * @param tableCellAddress a cell address, e.g. "foo.1.4"
  1248. * @return string the text from the specified cell
  1249. */
  1250. // This regular expression matches "tableName.row.column"
  1251. // For example, "mytable.3.4"
  1252. pattern = /(.*)\.(\d+)\.(\d+)/;
  1253. if(!pattern.test(tableCellAddress)) {
  1254. throw new SeleniumError("Invalid target format. Correct format is tableName.rowNum.columnNum");
  1255. }
  1256. pieces = tableCellAddress.match(pattern);
  1257. tableName = pieces[1];
  1258. row = pieces[2];
  1259. col = pieces[3];
  1260. var table = this.browserbot.findElement(tableName);
  1261. if (row > table.rows.length) {
  1262. Assert.fail("Cannot access row " + row + " - table has " + table.rows.length + " rows");
  1263. }
  1264. else if (col > table.rows[row].cells.length) {
  1265. Assert.fail("Cannot access column " + col + " - table row has " + table.rows[row].cells.length + " columns");
  1266. }
  1267. else {
  1268. actualContent = getText(table.rows[row].cells[col]);
  1269. return actualContent.trim();
  1270. }
  1271. return null;
  1272. };
  1273. Selenium.prototype.getSelectedLabels = function(selectLocator) {
  1274. /** Gets all option labels (visible text) for selected options in the specified select or multi-select element.
  1275. *
  1276. * @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
  1277. * @return string[] an array of all selected option labels in the specified select drop-down
  1278. */
  1279. return this.findSelectedOptionProperties(selectLocator, "text");
  1280. }
  1281. Selenium.prototype.getSelectedLabel = function(selectLocator) {
  1282. /** Gets option label (visible text) for selected option in the specified select element.
  1283. *
  1284. * @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
  1285. * @return string the selected option label in the specified select drop-down
  1286. */
  1287. return this.findSelectedOptionProperty(selectLocator, "text");
  1288. }
  1289. Selenium.prototype.getSelectedValues = function(selectLocator) {
  1290. /** Gets all option values (value attributes) for selected options in the specified select or multi-select element.
  1291. *
  1292. * @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
  1293. * @return string[] an array of all selected option values in the specified select drop-down
  1294. */
  1295. return this.findSelectedOptionProperties(selectLocator, "value");
  1296. }
  1297. Selenium.prototype.getSelectedValue = function(selectLocator) {
  1298. /** Gets option value (value attribute) for selected option in the specified select element.
  1299. *
  1300. * @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
  1301. * @return string the selected option value in the specified select drop-down
  1302. */
  1303. return this.findSelectedOptionProperty(selectLocator, "value");
  1304. }
  1305. Selenium.prototype.getSelectedIndexes = function(selectLocator) {
  1306. /** Gets all option indexes (option number, starting at 0) for selected options in the specified select or multi-select element.
  1307. *
  1308. * @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
  1309. * @return string[] an array of all selected option indexes in the specified select drop-down
  1310. */
  1311. return this.findSelectedOptionProperties(selectLocator, "index");
  1312. }
  1313. Selenium.prototype.getSelectedIndex = function(selectLocator) {
  1314. /** Gets option index (option number, starting at 0) for selected option in the specified select element.
  1315. *
  1316. * @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
  1317. * @return string the selected option index in the specified select drop-down
  1318. */
  1319. return this.findSelectedOptionProperty(selectLocator, "index");
  1320. }
  1321. Selenium.prototype.getSelectedIds = function(selectLocator) {
  1322. /** Gets all option element IDs for selected options in the specified select or multi-select element.
  1323. *
  1324. * @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
  1325. * @return string[] an array of all selected option IDs in the specified select drop-down
  1326. */
  1327. return this.findSelectedOptionProperties(selectLocator, "id");
  1328. }
  1329. Selenium.prototype.getSelectedId = function(selectLocator) {
  1330. /** Gets option element ID for selected option in the specified select element.
  1331. *
  1332. * @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
  1333. * @return string the selected option ID in the specified select drop-down
  1334. */
  1335. return this.findSelectedOptionProperty(selectLocator, "id");
  1336. }
  1337. Selenium.prototype.isSomethingSelected = function(selectLocator) {
  1338. /** Determines whether some option in a drop-down menu is selected.
  1339. *
  1340. * @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
  1341. * @return boolean true if some option has been selected, false otherwise
  1342. */
  1343. var element = this.browserbot.findElement(selectLocator);
  1344. if (!("options" in element)) {
  1345. throw new SeleniumError("Specified element is not a Select (has no options)");
  1346. }
  1347. var selectedOptions = [];
  1348. for (var i = 0; i < element.options.length; i++) {
  1349. if (element.options[i].selected)
  1350. {
  1351. return true;
  1352. }
  1353. }
  1354. return false;
  1355. }
  1356. Selenium.prototype.findSelectedOptionProperties = function(locator, property) {
  1357. var element = this.browserbot.findElement(locator);
  1358. if (!("options" in element)) {
  1359. throw new SeleniumError("Specified element is not a Select (has no options)");
  1360. }
  1361. var selectedOptions = [];
  1362. for (var i = 0; i < element.options.length; i++) {
  1363. if (element.options[i].selected)
  1364. {
  1365. var propVal = element.options[i][property];
  1366. selectedOptions.push(propVal);
  1367. }
  1368. }
  1369. if (selectedOptions.length == 0) Assert.fail("No option selected");
  1370. return selectedOptions;
  1371. }
  1372. Selenium.prototype.findSelectedOptionProperty = function(locator, property) {
  1373. var selectedOptions = this.findSelectedOptionProperties(locator, property);
  1374. if (selectedOptions.length > 1) {
  1375. Assert.fail("More than one selected option!");
  1376. }
  1377. return selectedOptions[0];
  1378. }
  1379. Selenium.prototype.getSelectOptions = function(selectLocator) {
  1380. /** Gets all option labels in the specified select drop-down.
  1381. *
  1382. * @param selectLocator an <a href="#locators">element locator</a> identifying a drop-down menu
  1383. * @return string[] an array of all option labels in the specified select drop-down
  1384. */
  1385. var element = this.browserbot.findElement(selectLocator);
  1386. var selectOptions = [];
  1387. for (var i = 0; i < element.options.length; i++) {
  1388. var option = element.options[i].text;
  1389. selectOptions.push(option);
  1390. }
  1391. return selectOptions;
  1392. };
  1393. Selenium.prototype.getAttribute = function(attributeLocator) {
  1394. /**
  1395. * Gets the value of an element attribute. The value of the attribute may
  1396. * differ across browsers (this is the case for the "style" attribute, for
  1397. * example).
  1398. *
  1399. * @param attributeLocator an element locator followed by an &#064; sign and then the name of the attribute, e.g. "foo&#064;bar"
  1400. * @return string the value of the specified attribute
  1401. */
  1402. var result = this.browserbot.findAttribute(attributeLocator);
  1403. if (result == null) {
  1404. throw new SeleniumError("Could not find element attribute: " + attributeLocator);
  1405. }
  1406. return result;
  1407. };
  1408. Selenium.prototype.isTextPresent = function(pattern) {
  1409. /**
  1410. * Verifies that the specified text pattern appears somewhere on the rendered page shown to the user.
  1411. * @param pattern a <a href="#patterns">pattern</a> to match with the text of the page
  1412. * @return boolean true if the pattern matches the text, false otherwise
  1413. */
  1414. var allText = this.browserbot.bodyText();
  1415. var patternMatcher = new PatternMatcher(pattern);
  1416. if (patternMatcher.strategy == PatternMatcher.strategies.glob) {
  1417. if (pattern.indexOf("glob:")==0) {
  1418. pattern = pattern.substring("glob:".length); // strip off "glob:"
  1419. }
  1420. patternMatcher.matcher = new PatternMatcher.strategies.globContains(pattern);
  1421. }
  1422. else if (patternMatcher.strategy == PatternMatcher.strategies.exact) {
  1423. pattern = pattern.substring("exact:".length); // strip off "exact:"
  1424. return allText.indexOf(pattern) != -1;
  1425. }
  1426. return patternMatcher.matches(allText);
  1427. };
  1428. Selenium.prototype.isElementPresent = function(locator) {
  1429. /**
  1430. * Verifies that the specified element is somewhere on the page.
  1431. * @param locator an <a href="#locators">element locator</a>
  1432. * @return boolean true if the element is present, false otherwise
  1433. */
  1434. var element = this.browserbot.findElementOrNull(locator);
  1435. if (element == null) {
  1436. return false;
  1437. }
  1438. return true;
  1439. };
  1440. Selenium.prototype.isVisible = function(locator) {
  1441. /**
  1442. * Determines if the specified element is visible. An
  1443. * element can be rendered invisible by setting the CSS "visibility"
  1444. * property to "hidden", or the "display" property to "none", either for the
  1445. * element itself or one if its ancestors. This method will fail if
  1446. * the element is not present.
  1447. *
  1448. * @param locator an <a href="#locators">element locator</a>
  1449. * @return boolean true if the specified element is visible, false otherwise
  1450. */
  1451. var element;
  1452. element = this.browserbot.findElement(locator);
  1453. // DGF if it's an input tag of type "hidden" then it's not visible
  1454. if (element.tagName) {
  1455. var tagName = new String(element.tagName).toLowerCase();
  1456. if (tagName == "input") {
  1457. if (element.type) {
  1458. var elementType = new String(element.type).toLowerCase();
  1459. if (elementType == "hidden") {
  1460. return false;
  1461. }
  1462. }
  1463. }
  1464. }
  1465. var visibility = this.findEffectiveStyleProperty(element, "visibility");
  1466. var _isDisplayed = this._isDisplayed(element);
  1467. return (visibility != "hidden" && _isDisplayed);
  1468. };
  1469. Selenium.prototype.findEffectiveStyleProperty = function(element, property) {
  1470. var effectiveStyle = this.findEffectiveStyle(element);
  1471. var propertyValue = effectiveStyle[property];
  1472. if (propertyValue == 'inherit' && element.parentNode.style) {
  1473. return this.findEffectiveStyleProperty(element.parentNode, property);
  1474. }
  1475. return propertyValue;
  1476. };
  1477. Selenium.prototype._isDisplayed = function(element) {
  1478. var display = this.findEffectiveStyleProperty(element, "display");
  1479. if (display == "none") return false;
  1480. if (element.parentNode.style) {
  1481. return this._isDisplayed(element.parentNode);
  1482. }
  1483. return true;
  1484. };
  1485. Selenium.prototype.findEffectiveStyle = function(element) {
  1486. if (element.style == undefined) {
  1487. return undefined; // not a styled element
  1488. }
  1489. var window = this.browserbot.getCurrentWindow();
  1490. if (window.getComputedStyle) {
  1491. // DOM-Level-2-CSS
  1492. return window.getComputedStyle(element, null);
  1493. }
  1494. if (element.currentStyle) {
  1495. // non-standard IE alternative
  1496. return element.currentStyle;
  1497. // TODO: this won't really work in a general sense, as
  1498. // currentStyle is not identical to getComputedStyle()
  1499. // ... but it's good enough for "visibility"
  1500. }
  1501. if (window.document.defaultView && window.document.defaultView.getComputedStyle) {
  1502. return window.document.defaultView.getComputedStyle(element, null);
  1503. }
  1504. throw new SeleniumError("cannot determine effective stylesheet in this browser");
  1505. };
  1506. Selenium.prototype.isEditable = function(locator) {
  1507. /**
  1508. * Determines whether the specified input element is editable, ie hasn't been disabled.
  1509. * This method will fail if the specified element isn't an input element.
  1510. *
  1511. * @param locator an <a href="#locators">element locator</a>
  1512. * @return boolean true if the input element is editable, false otherwise
  1513. */
  1514. var element = this.browserbot.findElement(locator);
  1515. if (element.value == undefined) {
  1516. Assert.fail("Element " + locator + " is not an input.");
  1517. }
  1518. if (element.disabled) {
  1519. return false;
  1520. }
  1521. // DGF "readonly" is a bit goofy... it doesn't necessarily have a value
  1522. // You can write <input readonly value="black">
  1523. var readOnlyNode = element.getAttributeNode('readonly');
  1524. if (readOnlyNode) {
  1525. // DGF on IE, every input element has a readOnly node, but it may be false
  1526. if (typeof(readOnlyNode.nodeValue) == "boolean") {
  1527. var readOnly = readOnlyNode.nodeValue;
  1528. if (readOnly) {
  1529. return false;
  1530. }
  1531. } else {
  1532. return false;
  1533. }
  1534. }
  1535. return true;
  1536. };
  1537. Selenium.prototype.getAllButtons = function() {
  1538. /** Returns the IDs of all buttons on the page.
  1539. *
  1540. * <p>If a given button has no ID, it will appear as "" in this array.</p>
  1541. *
  1542. * @return string[] the IDs of all buttons on the page
  1543. */
  1544. return this.browserbot.getAllButtons();
  1545. };
  1546. Selenium.prototype.getAllLinks = function() {
  1547. /** Returns the IDs of all links on the page.
  1548. *
  1549. * <p>If a given link has no ID, it will appear as "" in this array.</p>
  1550. *
  1551. * @return string[] the IDs of all links on the page
  1552. */
  1553. return this.browserbot.getAllLinks();
  1554. };
  1555. Selenium.prototype.getAllFields = function() {
  1556. /** Returns the IDs of all input fields on the page.
  1557. *
  1558. * <p>If a given field has no ID, it will appear as "" in this array.</p>
  1559. *
  1560. * @return string[] the IDs of all field on the page
  1561. */
  1562. return this.browserbot.getAllFields();
  1563. };
  1564. Selenium.prototype.getAttributeFromAllWindows = function(attributeName) {
  1565. /** Returns every instance of some attribute from all known windows.
  1566. *
  1567. * @param attributeName name of an attribute on the windows
  1568. * @return string[] the set of values of this attribute from all known windows.
  1569. */
  1570. var attributes = new Array();
  1571. var win = selenium.browserbot.topWindow;
  1572. // DGF normally you should use []s instead of eval "win."+attributeName
  1573. // but in this case, attributeName may contain dots (e.g. document.title)
  1574. // in that case, we have no choice but to use eval...
  1575. attributes.push(eval("win."+attributeName));
  1576. for (var windowName in this.browserbot.openedWindows)
  1577. {
  1578. try {
  1579. win = selenium.browserbot.openedWindows[windowName];
  1580. attributes.push(eval("win."+attributeName));
  1581. } catch (e) {} // DGF If we miss one... meh. It's probably closed or inaccessible anyway.
  1582. }
  1583. return attributes;
  1584. };
  1585. Selenium.prototype.findWindow = function(soughtAfterWindowPropertyValue) {
  1586. var targetPropertyName = "name";
  1587. if (soughtAfterWindowPropertyValue.match("^title=")) {
  1588. targetPropertyName = "document.title";
  1589. soughtAfterWindowPropertyValue = soughtAfterWindowPropertyValue.replace(/^title=/, "");
  1590. }
  1591. else {
  1592. // matching "name":
  1593. // If we are not in proxy injection mode, then the top-level test window will be named selenium_myiframe.
  1594. // But as far as the interface goes, we are expected to match a blank string to this window, if
  1595. // we are searching with respect to the widow name.
  1596. // So make a special case so that this logic will work:
  1597. if (PatternMatcher.matches(soughtAfterWindowPropertyValue, "")) {
  1598. return this.browserbot.getCurrentWindow();
  1599. }
  1600. }
  1601. // DGF normally you should use []s instead of eval "win."+attributeName
  1602. // but in this case, attributeName may contain dots (e.g. document.title)
  1603. // in that case, we have no choice but to use eval...
  1604. if (PatternMatcher.matches(soughtAfterWindowPropertyValue, eval("this.browserbot.topWindow." + targetPropertyName))) {
  1605. return this.browserbot.topWindow;
  1606. }
  1607. for (windowName in selenium.browserbot.openedWindows) {
  1608. var openedWindow = selenium.browserbot.openedWindows[windowName];
  1609. if (PatternMatcher.matches(soughtAfterWindowPropertyValue, eval("openedWindow." + targetPropertyName))) {
  1610. return openedWindow;
  1611. }
  1612. }
  1613. throw new SeleniumError("could not find window with property " + targetPropertyName + " matching " + soughtAfterWindowPropertyValue);
  1614. };
  1615. Selenium.prototype.doDragdrop = function(locator, movementsString) {
  1616. /** deprecated - use dragAndDrop instead
  1617. *
  1618. * @param locator an element locator
  1619. * @param movementsString offset in pixels from the current location to which the element should be moved, e.g., "+70,-300"
  1620. */
  1621. this.doDragAndDrop(locator, movementsString);
  1622. };
  1623. Selenium.prototype.doSetMouseSpeed = function(pixels) {
  1624. /** Configure the number of pixels between "mousemove" events during dragAndDrop commands (default=10).
  1625. * <p>Setting this value to 0 means that we'll send a "mousemove" event to every single pixel
  1626. * in between the start location and the end location; that can be very slow, and may
  1627. * cause some browsers to force the JavaScript to timeout.</p>
  1628. *
  1629. * <p>If the mouse speed is greater than the distance between the two dragged objects, we'll
  1630. * just send one "mousemove" at the start location and then one final one at the end location.</p>
  1631. * @param pixels the number of pixels between "mousemove" events
  1632. */
  1633. this.mouseSpeed = pixels;
  1634. }
  1635. Selenium.prototype.getMouseSpeed = function() {
  1636. /** Returns the number of pixels between "mousemove" events during dragAndDrop commands (default=10).
  1637. *
  1638. * @return number the number of pixels between "mousemove" events during dragAndDrop commands (default=10)
  1639. */
  1640. this.mouseSpeed = pixels;
  1641. }
  1642. Selenium.prototype.doDragAndDrop = function(locator, movementsString) {
  1643. /** Drags an element a certain distance and then drops it
  1644. * @param locator an element locator
  1645. * @param movementsString offset in pixels from the current location to which the element should be moved, e.g., "+70,-300"
  1646. */
  1647. var element = this.browserbot.findElement(locator);
  1648. var clientStartXY = getClientXY(element)
  1649. var clientStartX = clientStartXY[0];
  1650. var clientStartY = clientStartXY[1];
  1651. var movements = movementsString.split(/,/);
  1652. var movementX = Number(movements[0]);
  1653. var movementY = Number(movements[1]);
  1654. var clientFinishX = ((clientStartX + movementX) < 0) ? 0 : (clientStartX + movementX);
  1655. var clientFinishY = ((clientStartY + movementY) < 0) ? 0 : (clientStartY + movementY);
  1656. var mouseSpeed = this.mouseSpeed;
  1657. var move = function(current, dest) {
  1658. if (current == dest) return current;
  1659. if (Math.abs(current - dest) < mouseSpeed) return dest;
  1660. return (current < dest) ? current + mouseSpeed : current - mouseSpeed;
  1661. }
  1662. this.browserbot.triggerMouseEvent(element, 'mousedown', true, clientStartX, clientStartY);
  1663. this.browserbot.triggerMouseEvent(element, 'mousemove', true, clientStartX, clientStartY);
  1664. var clientX = clientStartX;
  1665. var clientY = clientStartY;
  1666. while ((clientX != clientFinishX) || (clientY != clientFinishY)) {
  1667. clientX = move(clientX, clientFinishX);
  1668. clientY = move(clientY, clientFinishY);
  1669. this.browserbot.triggerMouseEvent(element, 'mousemove', true, clientX, clientY);
  1670. }
  1671. this.browserbot.triggerMouseEvent(element, 'mousemove', true, clientFinishX, clientFinishY);
  1672. this.browserbot.triggerMouseEvent(element, 'mouseup', true, clientFinishX, clientFinishY);
  1673. };
  1674. Selenium.prototype.doDragAndDropToObject = function(locatorOfObjectToBeDragged, locatorOfDragDestinationObject) {
  1675. /** Drags an element and drops it on another element
  1676. *
  1677. * @param locatorOfObjectToBeDragged an element to be dragged
  1678. * @param locatorOfDragDestinationObject an element whose location (i.e., whose center-most pixel) will be the point where locatorOfObjectToBeDragged is dropped
  1679. */
  1680. var startX = this.getElementPositionLeft(locatorOfObjectToBeDragged);
  1681. var startY = this.getElementPositionTop(locatorOfObjectToBeDragged);
  1682. var destinationLeftX = this.getElementPositionLeft(locatorOfDragDestinationObject);
  1683. var destinationTopY = this.getElementPositionTop(locatorOfDragDestinationObject);
  1684. var destinationWidth = this.getElementWidth(locatorOfDragDestinationObject);
  1685. var destinationHeight = this.getElementHeight(locatorOfDragDestinationObject);
  1686. var endX = Math.round(destinationLeftX + (destinationWidth / 2));
  1687. var endY = Math.round(destinationTopY + (destinationHeight / 2));
  1688. var deltaX = endX - startX;
  1689. var deltaY = endY - startY;
  1690. var movementsString = "" + deltaX + "," + deltaY;
  1691. this.doDragAndDrop(locatorOfObjectToBeDragged, movementsString);
  1692. };
  1693. Selenium.prototype.doWindowFocus = function() {
  1694. /** Gives focus to the currently selected window
  1695. *
  1696. */
  1697. this.browserbot.getCurrentWindow().focus();
  1698. };
  1699. Selenium.prototype.doWindowMaximize = function() {
  1700. /** Resize currently selected window to take up the entire screen
  1701. *
  1702. */
  1703. var window = this.browserbot.getCurrentWindow();
  1704. if (window!=null && window.screen) {
  1705. window.moveTo(0,0);
  1706. window.resizeTo(screen.availWidth, screen.availHeight);
  1707. }
  1708. };
  1709. Selenium.prototype.getAllWindowIds = function() {
  1710. /** Returns the IDs of all windows that the browser knows about.
  1711. *
  1712. * @return string[] the IDs of all windows that the browser knows about.
  1713. */
  1714. return this.getAttributeFromAllWindows("id");
  1715. };
  1716. Selenium.prototype.getAllWindowNames = function() {
  1717. /** Returns the names of all windows that the browser knows about.
  1718. *
  1719. * @return string[] the names of all windows that the browser knows about.
  1720. */
  1721. return this.getAttributeFromAllWindows("name");
  1722. };
  1723. Selenium.prototype.getAllWindowTitles = function() {
  1724. /** Returns the titles of all windows that the browser knows about.
  1725. *
  1726. * @return string[] the titles of all windows that the browser knows about.
  1727. */
  1728. return this.getAttributeFromAllWindows("document.title");
  1729. };
  1730. Selenium.prototype.getHtmlSource = function() {
  1731. /** Returns the entire HTML source between the opening and
  1732. * closing "html" tags.
  1733. *
  1734. * @return string the entire HTML source
  1735. */
  1736. return this.browserbot.getDocument().getElementsByTagName("html")[0].innerHTML;
  1737. };
  1738. Selenium.prototype.doSetCursorPosition = function(locator, position) {
  1739. /**
  1740. * Moves the text cursor to the specified position in the given input element or textarea.
  1741. * This method will fail if the specified element isn't an input element or textarea.
  1742. *
  1743. * @param locator an <a href="#locators">element locator</a> pointing to an input element or textarea
  1744. * @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.
  1745. */
  1746. var element = this.browserbot.findElement(locator);
  1747. if (element.value == undefined) {
  1748. Assert.fail("Element " + locator + " is not an input.");
  1749. }
  1750. if (position == -1) {
  1751. position = element.value.length;
  1752. }
  1753. if( element.setSelectionRange && !browserVersion.isOpera) {
  1754. element.focus();
  1755. element.setSelectionRange(/*start*/position,/*end*/position);
  1756. }
  1757. else if( element.createTextRange ) {
  1758. triggerEvent(element, 'focus', false);
  1759. var range = element.createTextRange();
  1760. range.collapse(true);
  1761. range.moveEnd('character',position);
  1762. range.moveStart('character',position);
  1763. range.select();
  1764. }
  1765. }
  1766. Selenium.prototype.getElementIndex = function(locator) {
  1767. /**
  1768. * Get the relative index of an element to its parent (starting from 0). The comment node and empty text node
  1769. * will be ignored.
  1770. *
  1771. * @param locator an <a href="#locators">element locator</a> pointing to an element
  1772. * @return number of relative index of the element to its parent (starting from 0)
  1773. */
  1774. var element = this.browserbot.findElement(locator);
  1775. var previousSibling;
  1776. var index = 0;
  1777. while ((previousSibling = element.previousSibling) != null) {
  1778. if (!this._isCommentOrEmptyTextNode(previousSibling)) {
  1779. index++;
  1780. }
  1781. element = previousSibling;
  1782. }
  1783. return index;
  1784. }
  1785. Selenium.prototype.isOrdered = function(locator1, locator2) {
  1786. /**
  1787. * Check if these two elements have same parent and are ordered siblings in the DOM. Two same elements will
  1788. * not be considered ordered.
  1789. *
  1790. * @param locator1 an <a href="#locators">element locator</a> pointing to the first element
  1791. * @param locator2 an <a href="#locators">element locator</a> pointing to the second element
  1792. * @return boolean true if element1 is the previous sibling of element2, false otherwise
  1793. */
  1794. var element1 = this.browserbot.findElement(locator1);
  1795. var element2 = this.browserbot.findElement(locator2);
  1796. if (element1 === element2) return false;
  1797. var previousSibling;
  1798. while ((previousSibling = element2.previousSibling) != null) {
  1799. if (previousSibling === element1) {
  1800. return true;
  1801. }
  1802. element2 = previousSibling;
  1803. }
  1804. return false;
  1805. }
  1806. Selenium.prototype._isCommentOrEmptyTextNode = function(node) {
  1807. return node.nodeType == 8 || ((node.nodeType == 3) && !(/[^\t\n\r ]/.test(node.data)));
  1808. }
  1809. Selenium.prototype.getElementPositionLeft = function(locator) {
  1810. /**
  1811. * Retrieves the horizontal position of an element
  1812. *
  1813. * @param locator an <a href="#locators">element locator</a> pointing to an element OR an element itself
  1814. * @return number of pixels from the edge of the frame.
  1815. */
  1816. var element;
  1817. if ("string"==typeof locator) {
  1818. element = this.browserbot.findElement(locator);
  1819. }
  1820. else {
  1821. element = locator;
  1822. }
  1823. var x = element.offsetLeft;
  1824. var elementParent = element.offsetParent;
  1825. while (elementParent != null)
  1826. {
  1827. if(document.all)
  1828. {
  1829. if( (elementParent.tagName != "TABLE") && (elementParent.tagName != "BODY") )
  1830. {
  1831. x += elementParent.clientLeft;
  1832. }
  1833. }
  1834. else // Netscape/DOM
  1835. {
  1836. if(elementParent.tagName == "TABLE")
  1837. {
  1838. var parentBorder = parseInt(elementParent.border);
  1839. if(isNaN(parentBorder))
  1840. {
  1841. var parentFrame = elementParent.getAttribute('frame');
  1842. if(parentFrame != null)
  1843. {
  1844. x += 1;
  1845. }
  1846. }
  1847. else if(parentBorder > 0)
  1848. {
  1849. x += parentBorder;
  1850. }
  1851. }
  1852. }
  1853. x += elementParent.offsetLeft;
  1854. elementParent = elementParent.offsetParent;
  1855. }
  1856. return x;
  1857. };
  1858. Selenium.prototype.getElementPositionTop = function(locator) {
  1859. /**
  1860. * Retrieves the vertical position of an element
  1861. *
  1862. * @param locator an <a href="#locators">element locator</a> pointing to an element OR an element itself
  1863. * @return number of pixels from the edge of the frame.
  1864. */
  1865. var element;
  1866. if ("string"==typeof locator) {
  1867. element = this.browserbot.findElement(locator);
  1868. }
  1869. else {
  1870. element = locator;
  1871. }
  1872. var y = 0;
  1873. while (element != null)
  1874. {
  1875. if(document.all)
  1876. {
  1877. if( (element.tagName != "TABLE") && (element.tagName != "BODY") )
  1878. {
  1879. y += element.clientTop;
  1880. }
  1881. }
  1882. else // Netscape/DOM
  1883. {
  1884. if(element.tagName == "TABLE")
  1885. {
  1886. var parentBorder = parseInt(element.border);
  1887. if(isNaN(parentBorder))
  1888. {
  1889. var parentFrame = element.getAttribute('frame');
  1890. if(parentFrame != null)
  1891. {
  1892. y += 1;
  1893. }
  1894. }
  1895. else if(parentBorder > 0)
  1896. {
  1897. y += parentBorder;
  1898. }
  1899. }
  1900. }
  1901. y += element.offsetTop;
  1902. // Netscape can get confused in some cases, such that the height of the parent is smaller
  1903. // than that of the element (which it shouldn't really be). If this is the case, we need to
  1904. // exclude this element, since it will result in too large a 'top' return value.
  1905. if (element.offsetParent && element.offsetParent.offsetHeight && element.offsetParent.offsetHeight < element.offsetHeight)
  1906. {
  1907. // skip the parent that's too small
  1908. element = element.offsetParent.offsetParent;
  1909. }
  1910. else
  1911. {
  1912. // Next up...
  1913. element = element.offsetParent;
  1914. }
  1915. }
  1916. return y;
  1917. };
  1918. Selenium.prototype.getElementWidth = function(locator) {
  1919. /**
  1920. * Retrieves the width of an element
  1921. *
  1922. * @param locator an <a href="#locators">element locator</a> pointing to an element
  1923. * @return number width of an element in pixels
  1924. */
  1925. var element = this.browserbot.findElement(locator);
  1926. return element.offsetWidth;
  1927. };
  1928. Selenium.prototype.getElementHeight = function(locator) {
  1929. /**
  1930. * Retrieves the height of an element
  1931. *
  1932. * @param locator an <a href="#locators">element locator</a> pointing to an element
  1933. * @return number height of an element in pixels
  1934. */
  1935. var element = this.browserbot.findElement(locator);
  1936. return element.offsetHeight;
  1937. };
  1938. Selenium.prototype.getCursorPosition = function(locator) {
  1939. /**
  1940. * Retrieves the text cursor position in the given input element or textarea; beware, this may not work perfectly on all browsers.
  1941. *
  1942. * <p>Specifically, if the cursor/selection has been cleared by JavaScript, this command will tend to
  1943. * 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>
  1944. * This method will fail if the specified element isn't an input element or textarea, or there is no cursor in the element.
  1945. *
  1946. * @param locator an <a href="#locators">element locator</a> pointing to an input element or textarea
  1947. * @return number the numerical position of the cursor in the field
  1948. */
  1949. var element = this.browserbot.findElement(locator);
  1950. var doc = this.browserbot.getDocument();
  1951. var win = this.browserbot.getCurrentWindow();
  1952. if( doc.selection && !browserVersion.isOpera){
  1953. try {
  1954. var selectRange = doc.selection.createRange().duplicate();
  1955. var elementRange = element.createTextRange();
  1956. selectRange.move("character",0);
  1957. elementRange.move("character",0);
  1958. var inRange1 = selectRange.inRange(elementRange);
  1959. var inRange2 = elementRange.inRange(selectRange);
  1960. elementRange.setEndPoint("EndToEnd", selectRange);
  1961. } catch (e) {
  1962. Assert.fail("There is no cursor on this page!");
  1963. }
  1964. var answer = String(elementRange.text).replace(/\r/g,"").length;
  1965. return answer;
  1966. } else {
  1967. if (typeof(element.selectionStart) != "undefined") {
  1968. if (win.getSelection && typeof(win.getSelection().rangeCount) != undefined && win.getSelection().rangeCount == 0) {
  1969. Assert.fail("There is no cursor on this page!");
  1970. }
  1971. return element.selectionStart;
  1972. }
  1973. }
  1974. throw new Error("Couldn't detect cursor position on this browser!");
  1975. }
  1976. Selenium.prototype.getExpression = function(expression) {
  1977. /**
  1978. * Returns the specified expression.
  1979. *
  1980. * <p>This is useful because of JavaScript preprocessing.
  1981. * It is used to generate commands like assertExpression and waitForExpression.</p>
  1982. *
  1983. * @param expression the value to return
  1984. * @return string the value passed in
  1985. */
  1986. return expression;
  1987. }
  1988. Selenium.prototype.getXpathCount = function(xpath) {
  1989. /**
  1990. * Returns the number of nodes that match the specified xpath, eg. "//table" would give
  1991. * the number of tables.
  1992. *
  1993. * @param xpath the xpath expression to evaluate. do NOT wrap this expression in a 'count()' function; we will do that for you.
  1994. * @return number the number of nodes that match the specified xpath
  1995. */
  1996. var result = this.browserbot.evaluateXPathCount(xpath, this.browserbot.getDocument());
  1997. return result;
  1998. }
  1999. Selenium.prototype.doAssignId = function(locator, identifier) {
  2000. /**
  2001. * Temporarily sets the "id" attribute of the specified element, so you can locate it in the future
  2002. * using its ID rather than a slow/complicated XPath. This ID will disappear once the page is
  2003. * reloaded.
  2004. * @param locator an <a href="#locators">element locator</a> pointing to an element
  2005. * @param identifier a string to be used as the ID of the specified element
  2006. */
  2007. var element = this.browserbot.findElement(locator);
  2008. element.id = identifier;
  2009. }
  2010. Selenium.prototype.doAllowNativeXpath = function(allow) {
  2011. /**
  2012. * Specifies whether Selenium should use the native in-browser implementation
  2013. * of XPath (if any native version is available); if you pass "false" to
  2014. * this function, we will always use our pure-JavaScript xpath library.
  2015. * Using the pure-JS xpath library can improve the consistency of xpath
  2016. * element locators between different browser vendors, but the pure-JS
  2017. * version is much slower than the native implementations.
  2018. * @param allow boolean, true means we'll prefer to use native XPath; false means we'll only use JS XPath
  2019. */
  2020. if ("false" == allow || "0" == allow) { // The strings "false" and "0" are true values in JS
  2021. allow = false;
  2022. }
  2023. this.browserbot.allowNativeXpath = allow;
  2024. }
  2025. Selenium.prototype.doIgnoreAttributesWithoutValue = function(ignore) {
  2026. /**
  2027. * Specifies whether Selenium will ignore xpath attributes that have no
  2028. * value, i.e. are the empty string, when using the non-native xpath
  2029. * evaluation engine. You'd want to do this for performance reasons in IE.
  2030. * However, this could break certain xpaths, for example an xpath that looks
  2031. * for an attribute whose value is NOT the empty string.
  2032. *
  2033. * The hope is that such xpaths are relatively rare, but the user should
  2034. * have the option of using them. Note that this only influences xpath
  2035. * evaluation when using the ajaxslt engine (i.e. not "javascript-xpath").
  2036. *
  2037. * @param ignore boolean, true means we'll ignore attributes without value
  2038. * at the expense of xpath "correctness"; false means
  2039. * we'll sacrifice speed for correctness.
  2040. */
  2041. if ('false' == ignore || '0' == ignore) {
  2042. ignore = false;
  2043. }
  2044. this.browserbot.ignoreAttributesWithoutValue = ignore;
  2045. }
  2046. Selenium.prototype.doWaitForCondition = function(script, timeout) {
  2047. /**
  2048. * Runs the specified JavaScript snippet repeatedly until it evaluates to "true".
  2049. * The snippet may have multiple lines, but only the result of the last line
  2050. * will be considered.
  2051. *
  2052. * <p>Note that, by default, the snippet will be run in the runner's test window, not in the window
  2053. * of your application. To get the window of your application, you can use
  2054. * the JavaScript snippet <code>selenium.browserbot.getCurrentWindow()</code>, and then
  2055. * run your JavaScript in there</p>
  2056. * @param script the JavaScript snippet to run
  2057. * @param timeout a timeout in milliseconds, after which this command will return with an error
  2058. */
  2059. return Selenium.decorateFunctionWithTimeout(function () {
  2060. var window = selenium.browserbot.getCurrentWindow();
  2061. return eval(script);
  2062. }, timeout);
  2063. };
  2064. Selenium.prototype.doWaitForCondition.dontCheckAlertsAndConfirms = true;
  2065. Selenium.prototype.doSetTimeout = function(timeout) {
  2066. /**
  2067. * Specifies the amount of time that Selenium will wait for actions to complete.
  2068. *
  2069. * <p>Actions that require waiting include "open" and the "waitFor*" actions.</p>
  2070. * The default timeout is 30 seconds.
  2071. * @param timeout a timeout in milliseconds, after which the action will return with an error
  2072. */
  2073. if (!timeout) {
  2074. timeout = Selenium.DEFAULT_TIMEOUT;
  2075. }
  2076. this.defaultTimeout = timeout;
  2077. }
  2078. Selenium.prototype.doWaitForPageToLoad = function(timeout) {
  2079. /**
  2080. * Waits for a new page to load.
  2081. *
  2082. * <p>You can use this command instead of the "AndWait" suffixes, "clickAndWait", "selectAndWait", "typeAndWait" etc.
  2083. * (which are only available in the JS API).</p>
  2084. *
  2085. * <p>Selenium constantly keeps track of new pages loading, and sets a "newPageLoaded"
  2086. * flag when it first notices a page load. Running any other Selenium command after
  2087. * turns the flag to false. Hence, if you want to wait for a page to load, you must
  2088. * wait immediately after a Selenium command that caused a page-load.</p>
  2089. * @param timeout a timeout in milliseconds, after which this command will return with an error
  2090. */
  2091. // in pi-mode, the test and the harness share the window; thus if we are executing this code, then we have loaded
  2092. if (window["proxyInjectionMode"] == null || !window["proxyInjectionMode"]) {
  2093. return this.makePageLoadCondition(timeout);
  2094. }
  2095. };
  2096. Selenium.prototype.doWaitForFrameToLoad = function(frameAddress, timeout) {
  2097. /**
  2098. * Waits for a new frame to load.
  2099. *
  2100. * <p>Selenium constantly keeps track of new pages and frames loading,
  2101. * and sets a "newPageLoaded" flag when it first notices a page load.</p>
  2102. *
  2103. * See waitForPageToLoad for more information.
  2104. *
  2105. * @param frameAddress FrameAddress from the server side
  2106. * @param timeout a timeout in milliseconds, after which this command will return with an error
  2107. */
  2108. // in pi-mode, the test and the harness share the window; thus if we are executing this code, then we have loaded
  2109. if (window["proxyInjectionMode"] == null || !window["proxyInjectionMode"]) {
  2110. return this.makePageLoadCondition(timeout);
  2111. }
  2112. };
  2113. Selenium.prototype._isNewPageLoaded = function() {
  2114. return this.browserbot.isNewPageLoaded();
  2115. };
  2116. Selenium.prototype.doWaitForPageToLoad.dontCheckAlertsAndConfirms = true;
  2117. /**
  2118. * Evaluate a parameter, performing JavaScript evaluation and variable substitution.
  2119. * If the string matches the pattern "javascript{ ... }", evaluate the string between the braces.
  2120. */
  2121. Selenium.prototype.preprocessParameter = function(value) {
  2122. var match = value.match(/^javascript\{((.|\r?\n)+)\}$/);
  2123. if (match && match[1]) {
  2124. return eval(match[1]).toString();
  2125. }
  2126. return this.replaceVariables(value);
  2127. };
  2128. /*
  2129. * Search through str and replace all variable references ${varName} with their
  2130. * value in storedVars.
  2131. */
  2132. Selenium.prototype.replaceVariables = function(str) {
  2133. var stringResult = str;
  2134. // Find all of the matching variable references
  2135. var match = stringResult.match(/\$\{\w+\}/g);
  2136. if (!match) {
  2137. return stringResult;
  2138. }
  2139. // For each match, lookup the variable value, and replace if found
  2140. for (var i = 0; match && i < match.length; i++) {
  2141. var variable = match[i]; // The replacement variable, with ${}
  2142. var name = variable.substring(2, variable.length - 1); // The replacement variable without ${}
  2143. var replacement = storedVars[name];
  2144. if (replacement != undefined) {
  2145. stringResult = stringResult.replace(variable, replacement);
  2146. }
  2147. }
  2148. return stringResult;
  2149. };
  2150. Selenium.prototype.getCookie = function() {
  2151. /**
  2152. * Return all cookies of the current page under test.
  2153. *
  2154. * @return string all cookies of the current page under test
  2155. */
  2156. var doc = this.browserbot.getDocument();
  2157. return doc.cookie;
  2158. };
  2159. Selenium.prototype.getCookieByName = function(name) {
  2160. /**
  2161. * Returns the value of the cookie with the specified name, or throws an error if the cookie is not present.
  2162. * @param name the name of the cookie
  2163. * @return string the value of the cookie
  2164. */
  2165. var v = this.browserbot.getCookieByName(name);
  2166. if (v === null) {
  2167. throw new SeleniumError("Cookie '"+name+"' was not found");
  2168. }
  2169. return v;
  2170. };
  2171. Selenium.prototype.isCookiePresent = function(name) {
  2172. /**
  2173. * Returns true if a cookie with the specified name is present, or false otherwise.
  2174. * @param name the name of the cookie
  2175. * @return boolean true if a cookie with the specified name is present, or false otherwise.
  2176. */
  2177. var v = this.browserbot.getCookieByName(name);
  2178. var absent = (v === null);
  2179. return !absent;
  2180. }
  2181. Selenium.prototype.doCreateCookie = function(nameValuePair, optionsString) {
  2182. /**
  2183. * Create a new cookie whose path and domain are same with those of current page
  2184. * under test, unless you specified a path for this cookie explicitly.
  2185. *
  2186. * @param nameValuePair name and value of the cookie in a format "name=value"
  2187. * @param optionsString options for the cookie. Currently supported options include 'path', 'max_age' and 'domain'.
  2188. * the optionsString's format is "path=/path/, max_age=60, domain=.foo.com". The order of options are irrelevant, the unit
  2189. * of the value of 'max_age' is second. Note that specifying a domain that isn't a subset of the current domain will
  2190. * usually fail.
  2191. */
  2192. var results = /[^\s=\[\]\(\),"\/\?@:;]+=[^\s=\[\]\(\),"\/\?@:;]*/.test(nameValuePair);
  2193. if (!results) {
  2194. throw new SeleniumError("Invalid parameter.");
  2195. }
  2196. var cookie = nameValuePair.trim();
  2197. results = /max_age=(\d+)/.exec(optionsString);
  2198. if (results) {
  2199. var expireDateInMilliseconds = (new Date()).getTime() + results[1] * 1000;
  2200. cookie += "; expires=" + new Date(expireDateInMilliseconds).toGMTString();
  2201. }
  2202. results = /path=([^\s,]+)[,]?/.exec(optionsString);
  2203. if (results) {
  2204. var path = results[1];
  2205. if (browserVersion.khtml) {
  2206. // Safari and conquerer don't like paths with / at the end
  2207. if ("/" != path) {
  2208. path = path.replace(/\/$/, "");
  2209. }
  2210. }
  2211. cookie += "; path=" + path;
  2212. }
  2213. results = /domain=([^\s,]+)[,]?/.exec(optionsString);
  2214. if (results) {
  2215. var domain = results[1];
  2216. cookie += "; domain=" + domain;
  2217. }
  2218. LOG.debug("Setting cookie to: " + cookie);
  2219. this.browserbot.getDocument().cookie = cookie;
  2220. }
  2221. Selenium.prototype.doDeleteCookie = function(name,optionsString) {
  2222. /**
  2223. * Delete a named cookie with specified path and domain. Be careful; to delete a cookie, you
  2224. * need to delete it using the exact same path and domain that were used to create the cookie.
  2225. * If the path is wrong, or the domain is wrong, the cookie simply won't be deleted. Also
  2226. * note that specifying a domain that isn't a subset of the current domain will usually fail.
  2227. *
  2228. * Since there's no way to discover at runtime the original path and domain of a given cookie,
  2229. * we've added an option called 'recurse' to try all sub-domains of the current domain with
  2230. * all paths that are a subset of the current path. Beware; this option can be slow. In
  2231. * big-O notation, it operates in O(n*m) time, where n is the number of dots in the domain
  2232. * name and m is the number of slashes in the path.
  2233. *
  2234. * @param name the name of the cookie to be deleted
  2235. * @param optionsString options for the cookie. Currently supported options include 'path', 'domain'
  2236. * and 'recurse.' The optionsString's format is "path=/path/, domain=.foo.com, recurse=true".
  2237. * The order of options are irrelevant. Note that specifying a domain that isn't a subset of
  2238. * the current domain will usually fail.
  2239. */
  2240. // set the expire time of the cookie to be deleted to one minute before now.
  2241. var path = "";
  2242. var domain = "";
  2243. var recurse = false;
  2244. var matched = false;
  2245. results = /path=([^\s,]+)[,]?/.exec(optionsString);
  2246. if (results) {
  2247. matched = true;
  2248. path = results[1];
  2249. }
  2250. results = /domain=([^\s,]+)[,]?/.exec(optionsString);
  2251. if (results) {
  2252. matched = true;
  2253. domain = results[1];
  2254. }
  2255. results = /recurse=([^\s,]+)[,]?/.exec(optionsString);
  2256. if (results) {
  2257. matched = true;
  2258. recurse = results[1];
  2259. if ("false" == recurse) {
  2260. recurse = false;
  2261. }
  2262. }
  2263. // Treat the entire optionsString as a path (for backwards compatibility)
  2264. if (optionsString && !matched) {
  2265. LOG.warn("Using entire optionsString as a path; please change the argument to deleteCookie to use path="+optionsString);
  2266. path = optionsString;
  2267. }
  2268. if (browserVersion.khtml) {
  2269. // Safari and conquerer don't like paths with / at the end
  2270. if ("/" != path) {
  2271. path = path.replace(/\/$/, "");
  2272. }
  2273. }
  2274. path = path.trim();
  2275. domain = domain.trim();
  2276. var cookieName = name.trim();
  2277. if (recurse) {
  2278. this.browserbot.recursivelyDeleteCookie(cookieName, domain, path);
  2279. } else {
  2280. this.browserbot.deleteCookie(cookieName, domain, path);
  2281. }
  2282. }
  2283. Selenium.prototype.doDeleteAllVisibleCookies = function() {
  2284. /** Calls deleteCookie with recurse=true on all cookies visible to the current page.
  2285. * As noted on the documentation for deleteCookie, recurse=true can be much slower
  2286. * than simply deleting the cookies using a known domain/path.
  2287. */
  2288. var win = this.browserbot.getCurrentWindow();
  2289. var doc = win.document;
  2290. var cookieNames = this.browserbot.getAllCookieNames(doc);
  2291. var domain = doc.domain;
  2292. var path = win.location.pathname;
  2293. for (var i = 0; i < cookieNames.length; i++) {
  2294. this.browserbot.recursivelyDeleteCookie(cookieNames[i], domain, path, win);
  2295. }
  2296. }
  2297. Selenium.prototype.doSetBrowserLogLevel = function(logLevel) {
  2298. /**
  2299. * Sets the threshold for browser-side logging messages; log messages beneath this threshold will be discarded.
  2300. * Valid logLevel strings are: "debug", "info", "warn", "error" or "off".
  2301. * To see the browser logs, you need to
  2302. * either show the log window in GUI mode, or enable browser-side logging in Selenium RC.
  2303. *
  2304. * @param logLevel one of the following: "debug", "info", "warn", "error" or "off"
  2305. */
  2306. if (logLevel == null || logLevel == "") {
  2307. throw new SeleniumError("You must specify a log level");
  2308. }
  2309. logLevel = logLevel.toLowerCase();
  2310. if (LOG.logLevels[logLevel] == null) {
  2311. throw new SeleniumError("Invalid log level: " + logLevel);
  2312. }
  2313. LOG.setLogLevelThreshold(logLevel);
  2314. }
  2315. Selenium.prototype.doRunScript = function(script) {
  2316. /**
  2317. * Creates a new "script" tag in the body of the current test window, and
  2318. * adds the specified text into the body of the command. Scripts run in
  2319. * this way can often be debugged more easily than scripts executed using
  2320. * Selenium's "getEval" command. Beware that JS exceptions thrown in these script
  2321. * tags aren't managed by Selenium, so you should probably wrap your script
  2322. * in try/catch blocks if there is any chance that the script will throw
  2323. * an exception.
  2324. * @param script the JavaScript snippet to run
  2325. */
  2326. var win = this.browserbot.getCurrentWindow();
  2327. var doc = win.document;
  2328. var scriptTag = doc.createElement("script");
  2329. scriptTag.type = "text/javascript"
  2330. scriptTag.text = script;
  2331. doc.body.appendChild(scriptTag);
  2332. }
  2333. Selenium.prototype.doAddLocationStrategy = function(strategyName, functionDefinition) {
  2334. /**
  2335. * Defines a new function for Selenium to locate elements on the page.
  2336. * For example,
  2337. * if you define the strategy "foo", and someone runs click("foo=blah"), we'll
  2338. * run your function, passing you the string "blah", and click on the element
  2339. * that your function
  2340. * returns, or throw an "Element not found" error if your function returns null.
  2341. *
  2342. * We'll pass three arguments to your function:
  2343. * <ul>
  2344. * <li>locator: the string the user passed in</li>
  2345. * <li>inWindow: the currently selected window</li>
  2346. * <li>inDocument: the currently selected document</li>
  2347. * </ul>
  2348. * The function must return null if the element can't be found.
  2349. *
  2350. * @param strategyName the name of the strategy to define; this should use only
  2351. * letters [a-zA-Z] with no spaces or other punctuation.
  2352. * @param functionDefinition a string defining the body of a function in JavaScript.
  2353. * For example: <code>return inDocument.getElementById(locator);</code>
  2354. */
  2355. if (!/^[a-zA-Z]+$/.test(strategyName)) {
  2356. throw new SeleniumError("Invalid strategy name: " + strategyName);
  2357. }
  2358. var strategyFunction;
  2359. try {
  2360. strategyFunction = new Function("locator", "inDocument", "inWindow", functionDefinition);
  2361. } catch (ex) {
  2362. throw new SeleniumError("Error evaluating function definition: " + extractExceptionMessage(ex));
  2363. }
  2364. var safeStrategyFunction = function() {
  2365. try {
  2366. return strategyFunction.apply(this, arguments);
  2367. } catch (ex) {
  2368. throw new SeleniumError("Error executing strategy function " + strategyName + ": " + extractExceptionMessage(ex));
  2369. }
  2370. }
  2371. this.browserbot.locationStrategies[strategyName] = safeStrategyFunction;
  2372. }
  2373. Selenium.prototype.doCaptureEntirePageScreenshot = function(filename, kwargs) {
  2374. /**
  2375. * Saves the entire contents of the current window canvas to a PNG file.
  2376. * Currently this only works in Mozilla and when running in chrome mode.
  2377. * Contrast this with the captureScreenshot command, which captures the
  2378. * contents of the OS viewport (i.e. whatever is currently being displayed
  2379. * on the monitor), and is implemented in the RC only. Implementation
  2380. * mostly borrowed from the Screengrab! Firefox extension. Please see
  2381. * http://www.screengrab.org for details.
  2382. *
  2383. * @param filename the path to the file to persist the screenshot as. No
  2384. * filename extension will be appended by default.
  2385. * Directories will not be created if they do not exist,
  2386. * and an exception will be thrown, possibly by native
  2387. * code.
  2388. * @param kwargs a kwargs string that modifies the way the screenshot
  2389. * is captured. Example: "background=#CCFFDD" .
  2390. * Currently valid options:
  2391. * <dl>
  2392. * <dt>background</dt>
  2393. * <dd>the background CSS for the HTML document. This
  2394. * may be useful to set for capturing screenshots of
  2395. * less-than-ideal layouts, for example where absolute
  2396. * positioning causes the calculation of the canvas
  2397. * dimension to fail and a black background is exposed
  2398. * (possibly obscuring black text).</dd>
  2399. * </dl>
  2400. */
  2401. // can only take screenshots in Mozilla chrome mode or IE (non-PI). But
  2402. // since IE support is HIGHLY EXPERIMENTAL, don't advertise it in the doc.
  2403. if (!browserVersion.isChrome && !browserVersion.isIE) {
  2404. throw new SeleniumError('takeScreenshot is only implemented for '
  2405. + "chrome and iexplore browsers, but the current browser isn't "
  2406. + 'one of them');
  2407. }
  2408. // do or do not ... there is no try
  2409. if (browserVersion.isIE) {
  2410. // targeting snapsIE >= 0.2
  2411. function getFailureMessage(exceptionMessage) {
  2412. var msg = 'Snapsie failed: ';
  2413. if (exceptionMessage) {
  2414. if (exceptionMessage ==
  2415. "Automation server can't create object") {
  2416. msg += 'Is it installed? Does it have permission to run '
  2417. 'as an add-on? See http://snapsie.sourceforge.net/';
  2418. }
  2419. else {
  2420. msg += exceptionMessage;
  2421. }
  2422. }
  2423. else {
  2424. msg += 'Undocumented error';
  2425. }
  2426. return msg;
  2427. }
  2428. if (typeof(runOptions) != 'undefined' &&
  2429. runOptions.isMultiWindowMode() == false) {
  2430. // framed mode
  2431. try {
  2432. new Snapsie().saveSnapshot(filename, 'selenium_myiframe');
  2433. }
  2434. catch (e) {
  2435. throw new SeleniumError(getFailureMessage(e.message));
  2436. }
  2437. }
  2438. else {
  2439. // multi-window mode
  2440. if (!this.snapsieSrc) {
  2441. // XXX - cache snapsie, and capture the screenshot as a
  2442. // callback. Definitely a hack, because we may be late taking
  2443. // the first screenshot, but saves us from polluting other code
  2444. // for now. I wish there were an easier way to get at the
  2445. // contents of a referenced script!
  2446. var snapsieUrl = (this.browserbot.buttonWindow.location.href)
  2447. .replace(/(Test|Remote)Runner\.html/, 'lib/snapsie.js');
  2448. var self = this;
  2449. new Ajax.Request(snapsieUrl, {
  2450. method: 'get'
  2451. , onSuccess: function(transport) {
  2452. self.snapsieSrc = transport.responseText;
  2453. self.doCaptureEntirePageScreenshot(filename, kwargs);
  2454. }
  2455. });
  2456. return;
  2457. }
  2458. // it's going into a string, so escape the backslashes
  2459. filename = filename.replace(/\\/g, '\\\\');
  2460. // this is sort of hackish. We insert a script into the document,
  2461. // and remove it before anyone notices.
  2462. var doc = selenium.browserbot.getDocument();
  2463. var script = doc.createElement('script');
  2464. var scriptContent = this.snapsieSrc
  2465. + 'try {'
  2466. + ' new Snapsie().saveSnapshot("' + filename + '");'
  2467. + '}'
  2468. + 'catch (e) {'
  2469. + ' document.getElementById("takeScreenshot").failure ='
  2470. + ' e.message;'
  2471. + '}';
  2472. script.id = 'takeScreenshot';
  2473. script.language = 'javascript';
  2474. script.text = scriptContent;
  2475. doc.body.appendChild(script);
  2476. script.parentNode.removeChild(script);
  2477. if (script.failure) {
  2478. throw new SeleniumError(getFailureMessage(script.failure));
  2479. }
  2480. }
  2481. return;
  2482. }
  2483. var grabber = {
  2484. prepareCanvas: function(width, height) {
  2485. var styleWidth = width + 'px';
  2486. var styleHeight = height + 'px';
  2487. var grabCanvas = document.getElementById('screenshot_canvas');
  2488. if (!grabCanvas) {
  2489. // create the canvas
  2490. var ns = 'http://www.w3.org/1999/xhtml';
  2491. grabCanvas = document.createElementNS(ns, 'html:canvas');
  2492. grabCanvas.id = 'screenshot_canvas';
  2493. grabCanvas.style.display = 'none';
  2494. document.documentElement.appendChild(grabCanvas);
  2495. }
  2496. grabCanvas.width = width;
  2497. grabCanvas.style.width = styleWidth;
  2498. grabCanvas.style.maxWidth = styleWidth;
  2499. grabCanvas.height = height;
  2500. grabCanvas.style.height = styleHeight;
  2501. grabCanvas.style.maxHeight = styleHeight;
  2502. return grabCanvas;
  2503. },
  2504. prepareContext: function(canvas, box) {
  2505. var context = canvas.getContext('2d');
  2506. context.clearRect(box.x, box.y, box.width, box.height);
  2507. context.save();
  2508. return context;
  2509. }
  2510. };
  2511. var SGNsUtils = {
  2512. dataUrlToBinaryInputStream: function(dataUrl) {
  2513. var nsIoService = Components.classes["@mozilla.org/network/io-service;1"]
  2514. .getService(Components.interfaces.nsIIOService);
  2515. var channel = nsIoService
  2516. .newChannelFromURI(nsIoService.newURI(dataUrl, null, null));
  2517. var binaryInputStream = Components.classes["@mozilla.org/binaryinputstream;1"]
  2518. .createInstance(Components.interfaces.nsIBinaryInputStream);
  2519. binaryInputStream.setInputStream(channel.open());
  2520. return binaryInputStream;
  2521. },
  2522. newFileOutputStream: function(nsFile) {
  2523. var writeFlag = 0x02; // write only
  2524. var createFlag = 0x08; // create
  2525. var truncateFlag = 0x20; // truncate
  2526. var fileOutputStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
  2527. .createInstance(Components.interfaces.nsIFileOutputStream);
  2528. fileOutputStream.init(nsFile,
  2529. writeFlag | createFlag | truncateFlag, 0664, null);
  2530. return fileOutputStream;
  2531. },
  2532. writeBinaryInputStreamToFileOutputStream:
  2533. function(binaryInputStream, fileOutputStream) {
  2534. var numBytes = binaryInputStream.available();
  2535. var bytes = binaryInputStream.readBytes(numBytes);
  2536. fileOutputStream.write(bytes, numBytes);
  2537. }
  2538. };
  2539. // compute dimensions
  2540. var window = this.browserbot.getCurrentWindow();
  2541. var doc = window.document.documentElement;
  2542. var box = {
  2543. x: 0,
  2544. y: 0,
  2545. width: doc.scrollWidth,
  2546. height: doc.scrollHeight
  2547. };
  2548. LOG.debug('computed dimensions');
  2549. var originalBackground = doc.style.background;
  2550. if (kwargs) {
  2551. var args = parse_kwargs(kwargs);
  2552. if (args.background) {
  2553. doc.style.background = args.background;
  2554. }
  2555. }
  2556. // grab
  2557. var format = 'png';
  2558. var canvas = grabber.prepareCanvas(box.width, box.height);
  2559. var context = grabber.prepareContext(canvas, box);
  2560. context.drawWindow(window, box.x, box.y, box.width, box.height,
  2561. 'rgb(0, 0, 0)');
  2562. context.restore();
  2563. var dataUrl = canvas.toDataURL("image/" + format);
  2564. LOG.debug('grabbed to canvas');
  2565. doc.style.background = originalBackground;
  2566. // save to file
  2567. var nsFile = Components.classes["@mozilla.org/file/local;1"]
  2568. .createInstance(Components.interfaces.nsILocalFile);
  2569. try {
  2570. nsFile.initWithPath(filename);
  2571. }
  2572. catch (e) {
  2573. if (/NS_ERROR_FILE_UNRECOGNIZED_PATH/.test(e.message)) {
  2574. // try using the opposite file separator
  2575. if (filename.indexOf('/') != -1) {
  2576. filename = filename.replace(/\//g, '\\');
  2577. }
  2578. else {
  2579. filename = filename.replace(/\\/g, '/');
  2580. }
  2581. nsFile.initWithPath(filename);
  2582. }
  2583. else {
  2584. throw e;
  2585. }
  2586. }
  2587. var binaryInputStream = SGNsUtils.dataUrlToBinaryInputStream(dataUrl);
  2588. var fileOutputStream = SGNsUtils.newFileOutputStream(nsFile);
  2589. SGNsUtils.writeBinaryInputStreamToFileOutputStream(binaryInputStream,
  2590. fileOutputStream);
  2591. fileOutputStream.close();
  2592. LOG.debug('saved to file');
  2593. };
  2594. Selenium.prototype.doRollup = function(rollupName, kwargs) {
  2595. /**
  2596. * Executes a command rollup, which is a series of commands with a unique
  2597. * name, and optionally arguments that control the generation of the set of
  2598. * commands. If any one of the rolled-up commands fails, the rollup is
  2599. * considered to have failed. Rollups may also contain nested rollups.
  2600. *
  2601. * @param rollupName the name of the rollup command
  2602. * @param kwargs keyword arguments string that influences how the
  2603. * rollup expands into commands
  2604. */
  2605. // we have to temporarily hijack the commandStarted, nextCommand(),
  2606. // commandComplete(), and commandError() methods of the TestLoop object.
  2607. // When the expanded rollup commands are done executing (or an error has
  2608. // occurred), we'll restore them to their original values.
  2609. var loop = currentTest || htmlTestRunner.currentTest;
  2610. var backupManager = {
  2611. backup: function() {
  2612. for (var item in this.data) {
  2613. this.data[item] = loop[item];
  2614. }
  2615. }
  2616. , restore: function() {
  2617. for (var item in this.data) {
  2618. loop[item] = this.data[item];
  2619. }
  2620. }
  2621. , data: {
  2622. requiresCallBack: null
  2623. , commandStarted: null
  2624. , nextCommand: null
  2625. , commandComplete: null
  2626. , commandError: null
  2627. , pendingRollupCommands: null
  2628. , rollupFailed: null
  2629. , rollupFailedMessage: null
  2630. }
  2631. };
  2632. var rule = RollupManager.getInstance().getRollupRule(rollupName);
  2633. var expandedCommands = rule.getExpandedCommands(kwargs);
  2634. // hold your breath ...
  2635. try {
  2636. backupManager.backup();
  2637. loop.requiresCallBack = false;
  2638. loop.commandStarted = function() {};
  2639. loop.nextCommand = function() {
  2640. if (this.pendingRollupCommands.length == 0) {
  2641. return null;
  2642. }
  2643. var command = this.pendingRollupCommands.shift();
  2644. return command;
  2645. };
  2646. loop.commandComplete = function(result) {
  2647. if (result.failed) {
  2648. this.rollupFailed = true;
  2649. this.rollupFailureMessages.push(result.failureMessage);
  2650. }
  2651. if (this.pendingRollupCommands.length == 0) {
  2652. result = {
  2653. failed: this.rollupFailed
  2654. , failureMessage: this.rollupFailureMessages.join('; ')
  2655. };
  2656. LOG.info('Rollup execution complete: ' + (result.failed
  2657. ? 'failed! (see error messages below)' : 'ok'));
  2658. backupManager.restore();
  2659. this.commandComplete(result);
  2660. }
  2661. };
  2662. loop.commandError = function(errorMessage) {
  2663. LOG.info('Rollup execution complete: bombed!');
  2664. backupManager.restore();
  2665. this.commandError(errorMessage);
  2666. };
  2667. loop.pendingRollupCommands = expandedCommands;
  2668. loop.rollupFailed = false;
  2669. loop.rollupFailureMessages = [];
  2670. }
  2671. catch (e) {
  2672. LOG.error('Rollup error: ' + e);
  2673. backupManager.restore();
  2674. }
  2675. };
  2676. /**
  2677. * Factory for creating "Option Locators".
  2678. * An OptionLocator is an object for dealing with Select options (e.g. for
  2679. * finding a specified option, or asserting that the selected option of
  2680. * Select element matches some condition.
  2681. * The type of locator returned by the factory depends on the locator string:
  2682. * label=<exp> (OptionLocatorByLabel)
  2683. * value=<exp> (OptionLocatorByValue)
  2684. * index=<exp> (OptionLocatorByIndex)
  2685. * id=<exp> (OptionLocatorById)
  2686. * <exp> (default is OptionLocatorByLabel).
  2687. */
  2688. function OptionLocatorFactory() {
  2689. }
  2690. OptionLocatorFactory.prototype.fromLocatorString = function(locatorString) {
  2691. var locatorType = 'label';
  2692. var locatorValue = locatorString;
  2693. // If there is a locator prefix, use the specified strategy
  2694. var result = locatorString.match(/^([a-zA-Z]+)=(.*)/);
  2695. if (result) {
  2696. locatorType = result[1];
  2697. locatorValue = result[2];
  2698. }
  2699. if (this.optionLocators == undefined) {
  2700. this.registerOptionLocators();
  2701. }
  2702. if (this.optionLocators[locatorType]) {
  2703. return new this.optionLocators[locatorType](locatorValue);
  2704. }
  2705. throw new SeleniumError("Unkown option locator type: " + locatorType);
  2706. };
  2707. /**
  2708. * To allow for easy extension, all of the option locators are found by
  2709. * searching for all methods of OptionLocatorFactory.prototype that start
  2710. * with "OptionLocatorBy".
  2711. * TODO: Consider using the term "Option Specifier" instead of "Option Locator".
  2712. */
  2713. OptionLocatorFactory.prototype.registerOptionLocators = function() {
  2714. this.optionLocators={};
  2715. for (var functionName in this) {
  2716. var result = /OptionLocatorBy([A-Z].+)$/.exec(functionName);
  2717. if (result != null) {
  2718. var locatorName = result[1].lcfirst();
  2719. this.optionLocators[locatorName] = this[functionName];
  2720. }
  2721. }
  2722. };
  2723. /**
  2724. * OptionLocator for options identified by their labels.
  2725. */
  2726. OptionLocatorFactory.prototype.OptionLocatorByLabel = function(label) {
  2727. this.label = label;
  2728. this.labelMatcher = new PatternMatcher(this.label);
  2729. this.findOption = function(element) {
  2730. for (var i = 0; i < element.options.length; i++) {
  2731. if (this.labelMatcher.matches(element.options[i].text)) {
  2732. return element.options[i];
  2733. }
  2734. }
  2735. throw new SeleniumError("Option with label '" + this.label + "' not found");
  2736. };
  2737. this.assertSelected = function(element) {
  2738. var selectedLabel = element.options[element.selectedIndex].text;
  2739. Assert.matches(this.label, selectedLabel)
  2740. };
  2741. };
  2742. /**
  2743. * OptionLocator for options identified by their values.
  2744. */
  2745. OptionLocatorFactory.prototype.OptionLocatorByValue = function(value) {
  2746. this.value = value;
  2747. this.valueMatcher = new PatternMatcher(this.value);
  2748. this.findOption = function(element) {
  2749. for (var i = 0; i < element.options.length; i++) {
  2750. if (this.valueMatcher.matches(element.options[i].value)) {
  2751. return element.options[i];
  2752. }
  2753. }
  2754. throw new SeleniumError("Option with value '" + this.value + "' not found");
  2755. };
  2756. this.assertSelected = function(element) {
  2757. var selectedValue = element.options[element.selectedIndex].value;
  2758. Assert.matches(this.value, selectedValue)
  2759. };
  2760. };
  2761. /**
  2762. * OptionLocator for options identified by their index.
  2763. */
  2764. OptionLocatorFactory.prototype.OptionLocatorByIndex = function(index) {
  2765. this.index = Number(index);
  2766. if (isNaN(this.index) || this.index < 0) {
  2767. throw new SeleniumError("Illegal Index: " + index);
  2768. }
  2769. this.findOption = function(element) {
  2770. if (element.options.length <= this.index) {
  2771. throw new SeleniumError("Index out of range. Only " + element.options.length + " options available");
  2772. }
  2773. return element.options[this.index];
  2774. };
  2775. this.assertSelected = function(element) {
  2776. Assert.equals(this.index, element.selectedIndex);
  2777. };
  2778. };
  2779. /**
  2780. * OptionLocator for options identified by their id.
  2781. */
  2782. OptionLocatorFactory.prototype.OptionLocatorById = function(id) {
  2783. this.id = id;
  2784. this.idMatcher = new PatternMatcher(this.id);
  2785. this.findOption = function(element) {
  2786. for (var i = 0; i < element.options.length; i++) {
  2787. if (this.idMatcher.matches(element.options[i].id)) {
  2788. return element.options[i];
  2789. }
  2790. }
  2791. throw new SeleniumError("Option with id '" + this.id + "' not found");
  2792. };
  2793. this.assertSelected = function(element) {
  2794. var selectedId = element.options[element.selectedIndex].id;
  2795. Assert.matches(this.id, selectedId)
  2796. };
  2797. };