element_finding_test.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. // Licensed to the Software Freedom Conservancy (SFC) under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. The SFC licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing,
  12. // software distributed under the License is distributed on an
  13. // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. // KIND, either express or implied. See the License for the
  15. // specific language governing permissions and limitations
  16. // under the License.
  17. 'use strict';
  18. var fail = require('assert').fail;
  19. var Browser = require('..').Browser,
  20. By = require('..').By,
  21. error = require('..').error,
  22. until = require('..').until,
  23. promise = require('../lib/promise'),
  24. test = require('../lib/test'),
  25. assert = require('../testing/assert'),
  26. Pages = test.Pages;
  27. test.suite(function(env) {
  28. var browsers = env.browsers;
  29. var driver;
  30. test.before(function*() {
  31. driver = yield env.builder().build();
  32. });
  33. after(function() {
  34. return driver.quit();
  35. });
  36. describe('finding elements', function() {
  37. test.it(
  38. 'should work after loading multiple pages in a row',
  39. function*() {
  40. yield driver.get(Pages.formPage);
  41. yield driver.get(Pages.xhtmlTestPage);
  42. yield driver.findElement(By.linkText('click me')).click();
  43. yield driver.wait(until.titleIs('We Arrive Here'), 5000);
  44. });
  45. describe('By.id()', function() {
  46. test.it('should work', function*() {
  47. yield driver.get(Pages.xhtmlTestPage);
  48. yield driver.findElement(By.id('linkId')).click();
  49. yield driver.wait(until.titleIs('We Arrive Here'), 5000);
  50. });
  51. test.it('should fail if ID not present on page', function*() {
  52. yield driver.get(Pages.formPage);
  53. return driver.findElement(By.id('nonExistantButton')).
  54. then(fail, function(e) {
  55. assert(e).instanceOf(error.NoSuchElementError);
  56. });
  57. });
  58. test.it(
  59. 'should find multiple elements by ID even though that is ' +
  60. 'malformed HTML',
  61. function*() {
  62. yield driver.get(Pages.nestedPage);
  63. let elements = yield driver.findElements(By.id('2'));
  64. assert(elements.length).equalTo(8);
  65. });
  66. });
  67. describe('By.linkText()', function() {
  68. test.it('should be able to click on link identified by text', function*() {
  69. yield driver.get(Pages.xhtmlTestPage);
  70. yield driver.findElement(By.linkText('click me')).click();
  71. yield driver.wait(until.titleIs('We Arrive Here'), 5000);
  72. });
  73. test.it(
  74. 'should be able to find elements by partial link text',
  75. function*() {
  76. yield driver.get(Pages.xhtmlTestPage);
  77. yield driver.findElement(By.partialLinkText('ick me')).click();
  78. yield driver.wait(until.titleIs('We Arrive Here'), 5000);
  79. });
  80. test.it('should work when link text contains equals sign', function*() {
  81. yield driver.get(Pages.xhtmlTestPage);
  82. let el = yield driver.findElement(By.linkText('Link=equalssign'));
  83. let id = yield el.getAttribute('id');
  84. assert(id).equalTo('linkWithEqualsSign');
  85. });
  86. test.it('matches by partial text when containing equals sign',
  87. function*() {
  88. yield driver.get(Pages.xhtmlTestPage);
  89. let link = yield driver.findElement(By.partialLinkText('Link='));
  90. let id = yield link.getAttribute('id');
  91. assert(id).equalTo('linkWithEqualsSign');
  92. });
  93. test.it('works when searching for multiple and text contains =',
  94. function*() {
  95. yield driver.get(Pages.xhtmlTestPage);
  96. let elements =
  97. yield driver.findElements(By.linkText('Link=equalssign'));
  98. assert(elements.length).equalTo(1);
  99. let id = yield elements[0].getAttribute('id');
  100. assert(id).equalTo('linkWithEqualsSign');
  101. });
  102. test.it(
  103. 'works when searching for multiple with partial text containing =',
  104. function*() {
  105. yield driver.get(Pages.xhtmlTestPage);
  106. let elements =
  107. yield driver.findElements(By.partialLinkText('Link='));
  108. assert(elements.length).equalTo(1);
  109. let id = yield elements[0].getAttribute('id');
  110. assert(id).equalTo('linkWithEqualsSign');
  111. });
  112. test.it('should be able to find multiple exact matches',
  113. function*() {
  114. yield driver.get(Pages.xhtmlTestPage);
  115. let elements = yield driver.findElements(By.linkText('click me'));
  116. assert(elements.length).equalTo(2);
  117. });
  118. test.it('should be able to find multiple partial matches',
  119. function*() {
  120. yield driver.get(Pages.xhtmlTestPage);
  121. let elements =
  122. yield driver.findElements(By.partialLinkText('ick me'));
  123. assert(elements.length).equalTo(2);
  124. });
  125. test.ignore(browsers(Browser.SAFARI)).
  126. it('works on XHTML pages', function*() {
  127. yield driver.get(test.whereIs('actualXhtmlPage.xhtml'));
  128. let el = yield driver.findElement(By.linkText('Foo'));
  129. return assert(el.getText()).equalTo('Foo');
  130. });
  131. });
  132. describe('By.name()', function() {
  133. test.it('should work', function*() {
  134. yield driver.get(Pages.formPage);
  135. let el = yield driver.findElement(By.name('checky'));
  136. yield assert(el.getAttribute('value')).equalTo('furrfu');
  137. });
  138. test.it('should find multiple elements with same name', function*() {
  139. yield driver.get(Pages.nestedPage);
  140. let elements = yield driver.findElements(By.name('checky'));
  141. assert(elements.length).greaterThan(1);
  142. });
  143. test.it(
  144. 'should be able to find elements that do not support name property',
  145. function*() {
  146. yield driver.get(Pages.nestedPage);
  147. yield driver.findElement(By.name('div1'));
  148. // Pass if this does not return an error.
  149. });
  150. test.it('shoudl be able to find hidden elements by name', function*() {
  151. yield driver.get(Pages.formPage);
  152. yield driver.findElement(By.name('hidden'));
  153. // Pass if this does not return an error.
  154. });
  155. });
  156. describe('By.className()', function() {
  157. test.it('should work', function*() {
  158. yield driver.get(Pages.xhtmlTestPage);
  159. let el = yield driver.findElement(By.className('extraDiv'));
  160. yield assert(el.getText()).startsWith('Another div starts here.');
  161. });
  162. test.it('should work when name is first name among many', function*() {
  163. yield driver.get(Pages.xhtmlTestPage);
  164. let el = yield driver.findElement(By.className('nameA'));
  165. yield assert(el.getText()).equalTo('An H2 title');
  166. });
  167. test.it('should work when name is last name among many', function*() {
  168. yield driver.get(Pages.xhtmlTestPage);
  169. let el = yield driver.findElement(By.className('nameC'));
  170. yield assert(el.getText()).equalTo('An H2 title');
  171. });
  172. test.it('should work when name is middle of many', function*() {
  173. yield driver.get(Pages.xhtmlTestPage);
  174. let el = yield driver.findElement(By.className('nameBnoise'));
  175. yield assert(el.getText()).equalTo('An H2 title');
  176. });
  177. test.it('should work when name surrounded by whitespace', function*() {
  178. yield driver.get(Pages.xhtmlTestPage);
  179. let el = yield driver.findElement(By.className('spaceAround'));
  180. yield assert(el.getText()).equalTo('Spaced out');
  181. });
  182. test.it('should fail if queried name only partially matches', function*() {
  183. yield driver.get(Pages.xhtmlTestPage);
  184. return driver.findElement(By.className('nameB')).
  185. then(fail, function(e) {
  186. assert(e).instanceOf(error.NoSuchElementError);
  187. });
  188. });
  189. test.it('should implicitly wait', function*() {
  190. var TIMEOUT_IN_MS = 1000;
  191. var EPSILON = TIMEOUT_IN_MS / 2;
  192. yield driver.manage().timeouts().implicitlyWait(TIMEOUT_IN_MS);
  193. yield driver.get(Pages.formPage);
  194. var start = new Date();
  195. return driver.findElement(By.id('nonExistantButton')).
  196. then(fail, function(e) {
  197. var end = new Date();
  198. assert(e).instanceOf(error.NoSuchElementError);
  199. assert(end - start).closeTo(TIMEOUT_IN_MS, EPSILON);
  200. });
  201. });
  202. test.it('should be able to find multiple matches', function*() {
  203. yield driver.get(Pages.xhtmlTestPage);
  204. let elements = yield driver.findElements(By.className('nameC'));
  205. assert(elements.length).greaterThan(1);
  206. });
  207. test.it('permits compound class names', function() {
  208. return driver.get(Pages.xhtmlTestPage)
  209. .then(() => driver.findElement(By.className('nameA nameC')))
  210. .then(el => el.getText())
  211. .then(text => assert(text).equalTo('An H2 title'));
  212. });
  213. });
  214. describe('By.xpath()', function() {
  215. test.it('should work with multiple matches', function*() {
  216. yield driver.get(Pages.xhtmlTestPage);
  217. let elements = yield driver.findElements(By.xpath('//div'));
  218. assert(elements.length).greaterThan(1);
  219. });
  220. test.it('should work for selectors using contains keyword', function*() {
  221. yield driver.get(Pages.nestedPage);
  222. yield driver.findElement(By.xpath('//a[contains(., "hello world")]'));
  223. // Pass if no error.
  224. });
  225. });
  226. describe('By.tagName()', function() {
  227. test.it('works', function*() {
  228. yield driver.get(Pages.formPage);
  229. let el = yield driver.findElement(By.tagName('input'));
  230. yield assert(el.getTagName()).equalTo('input');
  231. });
  232. test.it('can find multiple elements', function*() {
  233. yield driver.get(Pages.formPage);
  234. let elements = yield driver.findElements(By.tagName('input'));
  235. assert(elements.length).greaterThan(1);
  236. });
  237. });
  238. describe('By.css()', function() {
  239. test.it('works', function*() {
  240. yield driver.get(Pages.xhtmlTestPage);
  241. yield driver.findElement(By.css('div.content'));
  242. // Pass if no error.
  243. });
  244. test.it('can find multiple elements', function*() {
  245. yield driver.get(Pages.xhtmlTestPage);
  246. let elements = yield driver.findElements(By.css('p'));
  247. assert(elements.length).greaterThan(1);
  248. // Pass if no error.
  249. });
  250. test.it(
  251. 'should find first matching element when searching by ' +
  252. 'compound CSS selector',
  253. function*() {
  254. yield driver.get(Pages.xhtmlTestPage);
  255. let el =
  256. yield driver.findElement(By.css('div.extraDiv, div.content'));
  257. yield assert(el.getAttribute('class')).equalTo('content');
  258. });
  259. test.it('should be able to find multiple elements by compound selector',
  260. function*() {
  261. yield driver.get(Pages.xhtmlTestPage);
  262. let elements =
  263. yield driver.findElements(By.css('div.extraDiv, div.content'));
  264. return Promise.all([
  265. assertClassIs(elements[0], 'content'),
  266. assertClassIs(elements[1], 'extraDiv')
  267. ]);
  268. function assertClassIs(el, expected) {
  269. return assert(el.getAttribute('class')).equalTo(expected);
  270. }
  271. });
  272. // IE only supports short version option[selected].
  273. test.ignore(browsers(Browser.IE)).
  274. it('should be able to find element by boolean attribute', function*() {
  275. yield driver.get(test.whereIs(
  276. 'locators_tests/boolean_attribute_selected.html'));
  277. let el = yield driver.findElement(By.css('option[selected="selected"]'));
  278. yield assert(el.getAttribute('value')).equalTo('two');
  279. });
  280. test.it(
  281. 'should be able to find element with short ' +
  282. 'boolean attribute selector',
  283. function*() {
  284. yield driver.get(test.whereIs(
  285. 'locators_tests/boolean_attribute_selected.html'));
  286. let el = yield driver.findElement(By.css('option[selected]'));
  287. yield assert(el.getAttribute('value')).equalTo('two');
  288. });
  289. test.it(
  290. 'should be able to find element with short boolean attribute ' +
  291. 'selector on HTML4 page',
  292. function*() {
  293. yield driver.get(test.whereIs(
  294. 'locators_tests/boolean_attribute_selected_html4.html'));
  295. let el = yield driver.findElement(By.css('option[selected]'));
  296. yield assert(el.getAttribute('value')).equalTo('two');
  297. });
  298. });
  299. describe('by custom locator', function() {
  300. test.it('handles single element result', function*() {
  301. yield driver.get(Pages.javascriptPage);
  302. let link = yield driver.findElement(function(driver) {
  303. let links = driver.findElements(By.tagName('a'));
  304. return promise.filter(links, function(link) {
  305. return link.getAttribute('id').then(id => id === 'updatediv');
  306. }).then(links => links[0]);
  307. });
  308. yield assert(link.getText()).matches(/Update\s+a\s+div/);
  309. });
  310. test.it('uses first element if locator resolves to list', function*() {
  311. yield driver.get(Pages.javascriptPage);
  312. let link = yield driver.findElement(function() {
  313. return driver.findElements(By.tagName('a'));
  314. });
  315. yield assert(link.getText()).isEqualTo('Change the page title!');
  316. });
  317. test.it('fails if locator returns non-webelement value', function*() {
  318. yield driver.get(Pages.javascriptPage);
  319. let link = driver.findElement(function() {
  320. return driver.getTitle();
  321. });
  322. return link.then(
  323. () => fail('Should have failed'),
  324. (e) => assert(e).instanceOf(TypeError));
  325. });
  326. });
  327. describe('switchTo().activeElement()', function() {
  328. // SAFARI's new session response does not identify it as a W3C browser,
  329. // so the command is sent in the unsupported wire protocol format.
  330. test.ignore(browsers(Browser.SAFARI)).
  331. it('returns document.activeElement', function*() {
  332. yield driver.get(Pages.formPage);
  333. let email = yield driver.findElement(By.css('#email'));
  334. yield driver.executeScript('arguments[0].focus()', email);
  335. let ae = yield driver.switchTo().activeElement();
  336. let equal = yield driver.executeScript(
  337. 'return arguments[0] === arguments[1]', email, ae);
  338. assert(equal).isTrue();
  339. });
  340. });
  341. });
  342. });