| <!DOCTYPE html> |
| <!-- |
| Copyright 2010 WebDriver committers |
| Copyright 2010 Google Inc. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| <html> |
| <head> |
| <title>locator_test.html</title> |
| <script src="test_bootstrap.js"></script> |
| <script type="text/javascript"> |
| goog.require('bot'); |
| goog.require('bot.ErrorCode'); |
| goog.require('bot.locators'); |
| goog.require('goog.events.EventType'); |
| goog.require('goog.testing.PropertyReplacer'); |
| goog.require('goog.testing.jsunit'); |
| </script> |
| |
| <script type="text/javascript"> |
| function testCanFindById() { |
| var e = bot.locators.findElement({id: 'x'}); |
| |
| assertEquals('para', e.getAttribute('name')); |
| } |
| |
| function testCanFindByIdWhenElementIsAfterOneWithSameName() { |
| var e = bot.locators.findElement({id: 'after'}); |
| |
| assertEquals('right', e.getAttribute('name')); |
| } |
| |
| function testFindingByNameIgnoresComments() { |
| // This element is outside a form, forcing IE to fall back to using |
| // doc.getElementsByTagName. There are comments on this page that are |
| // returned in this collection. We access the "attributes" array of |
| // each element, which is clearly missing from comments. A roundabout way |
| // of doing this, but it works |
| |
| try { |
| var element = bot.locators.findElement({name: 'para'}); |
| assertNotNull(element); // this is expected |
| } catch (e) { |
| fail(e); // this is not. |
| } |
| } |
| |
| function testCanFindByNameOutsideOfAForm() { |
| var e = bot.locators.findElement({name: 'para'}); |
| |
| assertEquals('x', e.getAttribute('id')); |
| } |
| |
| function testWillNotFindAnElementByNameWhereNoMatchShouldBeFound() { |
| assertNull(bot.locators.findElement({name: 'foobar'})); |
| } |
| |
| function testCanFindByClassName() { |
| var dogs = bot.locators.findElement({className: 'dogs'}); |
| assertNotNull(dogs); |
| assertEquals('after', dogs.id); |
| } |
| |
| function testCannotSearchWithCompoundClassNames() { |
| assertThrows(goog.bind(bot.locators.findElement, null, |
| {className: 'feline cats'})); |
| } |
| |
| function testFindByClassNameReturnsFirstMatchingElement() { |
| var cats = bot.locators.findElement({className: 'cats'}); |
| assertNotNull(cats); |
| assertEquals('wrong', cats.id); |
| } |
| |
| function testCanFindByAnyOfAnElementsClassNames() { |
| var felines = bot.locators.findElement({className: 'feline'}); |
| var cats = bot.locators.findElement({className: 'cats'}); |
| |
| assertEquals(felines, cats); |
| assertEquals('wrong', cats.id); |
| } |
| |
| function testFindByClassNameReturnsNullIfNoMatchIsFound() { |
| assertNull(bot.locators.findElement({className: 'catsAndDogs'})); |
| } |
| |
| /** @bug http://code.google.com/p/selenium/issues/detail?id=1918 */ |
| function testFindSingleByClassName_targetClassHasDots() { |
| var found = bot.locators.findElement({className: 'name.with.dots'}); |
| assertEquals(goog.dom.$('dotted_1'), found); |
| } |
| |
| /** @bug http://code.google.com/p/selenium/issues/detail?id=1918 */ |
| function testFindManyByClassName_targetClassHasDot() { |
| var found = bot.locators.findElements({className: 'name.with.dots'}); |
| assertEquals(2, found.length); |
| assertEquals(goog.dom.$('dotted_1'), found[0]); |
| assertEquals(goog.dom.$('dotted_2'), found[1]); |
| } |
| |
| function testCanFindElementByCssSelector() { |
| if (!document['querySelectorAll']) { |
| return; // Skip this until we get selectors working on all browsers |
| } |
| |
| var after = bot.locators.findElement({css: '#wrong'}); |
| |
| assertNotNull(after); |
| assertEquals('wrong', after.id); |
| } |
| |
| function testShouldReturnNullIfNoCssMatchIsFound() { |
| if (!document['querySelectorAll']) { |
| return; // Skip this until we get selectors working on all browsers |
| } |
| |
| assertNull(bot.locators.findElement({css: '#uglyfish'})); |
| } |
| |
| function testShouldFindElementByMultipleSelectors() { |
| if (!document['querySelectorAll']) { |
| return; // Skip this until we get selectors working on all browsers |
| } |
| |
| var found = bot.locators.findElement({ css: '.dogs, #x' }); |
| assertNotNull(found); |
| assertEquals('x', found.id); |
| } |
| |
| function testShouldFindElementsByMultipleSelectors() { |
| if (!document['querySelectorAll']) { |
| return; // Skip this until we get selectors working on all browsers |
| } |
| |
| var found = bot.locators.findElements({ css: '.dogs, #x' }); |
| assertEquals(2, found.length); |
| assertEquals('x', found[0].id); |
| assertEquals('dogs', found[1].getAttribute('class')); |
| } |
| |
| function testShouldFindElementWithCommaInAttribute() { |
| assertNotNull(goog.bind(bot.locators.findElement, null, |
| {css: 'comma-in-alt[alt="has, a comma"]'})); |
| } |
| |
| function testCanLocateElementsUsingXPath() { |
| var doggies = bot.locators.findElement({xpath: "//*[@id = 'after']"}); |
| |
| assertNotNull(doggies); |
| assertEquals('after', doggies.id); |
| } |
| |
| function testCanLocateElementsUsingXPathInIframe() { |
| var frameDoc = window.frames[0].document; |
| var frameElement = bot.locators.findElement({xpath: '//body/h1'}, frameDoc); |
| assertNotNull(frameElement); |
| assertEquals('H1', frameElement.tagName); |
| } |
| |
| function testWillReturnNullIfNoMatchUsingXPathIsFound() { |
| assertNull(bot.locators.findElement({xpath: '//fish'})); |
| } |
| |
| function testShouldThrowInvalidSelectorErrorWhenXPathIsSyntacticallyInvalidInSingle() { |
| try { |
| bot.locators.findElement({xpath: 'this][isnot][valid'}); |
| fail('Should not have succeeded because the xpath expression is ' + |
| 'syntactically not correct'); |
| } catch (ex) { |
| //We expect an InvalidSelectorException because the xpath expression is |
| //syntactically invalid. |
| assertEquals(bot.ErrorCode.INVALID_SELECTOR_ERROR, ex.code); |
| } |
| } |
| |
| function testShouldThrowInvalidSelectorErrorWhenXPathReturnsAWrongTypeInSingle() { |
| try { |
| bot.locators.findElement({xpath: 'count(//fish)'}); |
| fail('Should not have succeeded because the xpath expression does ' + |
| 'not select an element.'); |
| } catch (ex) { |
| // We expect an exception because the XPath expression |
| // results in a number, not in an element. |
| assertEquals(bot.ErrorCode.INVALID_SELECTOR_ERROR, ex.code); |
| } |
| } |
| |
| function testCanFindMoreThanOneElementByName() { |
| var allFoos = bot.locators.findElements({name: 'foo'}); |
| |
| assertEquals(2, allFoos.length); |
| } |
| |
| function testCanFindManyElementsUsingCss() { |
| if (!document['querySelectorAll']) { |
| return; // Skip this until we get selectors working on all browsers |
| } |
| |
| var cats = bot.locators.findElements({css: '.cats'}); |
| |
| assertEquals(3, cats.length); |
| } |
| |
| function testCanFindManyElementsUsingClassName() { |
| var cats = bot.locators.findElements({className: 'cats'}); |
| |
| assertEquals(3, cats.length); |
| } |
| |
| function testCanFindManyElementsUsingAnId() { |
| var bad = bot.locators.findElements({id: 'illegal'}); |
| |
| assertEquals(4, bad.length); |
| } |
| |
| function testCanFindManyElementsViaXPath() { |
| var bad = bot.locators.findElements({xpath: '//*[@name = "after"]'}); |
| |
| assertEquals(2, bad.length); |
| } |
| |
| function testShouldThrowInvalidSelectorErrorWhenXPathIsSyntacticallyInvalidInMany() { |
| try { |
| bot.locators.findElements({xpath: 'this][isnot][valid'}); |
| fail('Should not have succeeded because the xpath expression is ' + |
| 'syntactically not correct.'); |
| } catch (ex) { |
| // We expect an InvalidSelectorException because the xpath expression is |
| // syntactically invalid. |
| assertEquals(bot.ErrorCode.INVALID_SELECTOR_ERROR, ex.code); |
| } |
| } |
| |
| function testShouldThrowInvalidSelectorErrorWhenXPathReturnsAWrongTypeInMany() { |
| try { |
| bot.locators.findElements({xpath: 'count(//fish)'}); |
| fail('Should not have succeeded because the xpath expression does ' + |
| 'not select an element.'); |
| } catch (ex) { |
| // We expect an exception because the XPath expression |
| // results in a number, not in an element. |
| assertEquals(bot.ErrorCode.INVALID_SELECTOR_ERROR, ex.code); |
| } |
| } |
| |
| function testCanFindElementByLinkText() { |
| var link = bot.locators.findElement({linkText: 'this is a link'}); |
| |
| assertEquals('link', bot.dom.getAttribute(link, 'id')); |
| } |
| |
| function testCanFindElementsByLinkText() { |
| var links = bot.locators.findElements({linkText: 'this is a link'}); |
| |
| assertEquals(5, links.length); |
| } |
| |
| function testShouldBeAbleToFindLinksWithNoText() { |
| var link = bot.locators.findElement({linkText: ''}); |
| assertNotNull(link); |
| assertEquals('empty-link', link.id); |
| |
| var links = bot.locators.findElements({linkText: ''}); |
| assertEquals(1, links.length); |
| assertEquals('empty-link', links[0].id); |
| } |
| |
| function testCanFindElementByPartialLinkText() { |
| var link = bot.locators.findElement({partialLinkText: 'is a'}); |
| |
| assertEquals('link', bot.dom.getAttribute(link, 'id')); |
| } |
| |
| function testCanFindElementsByPartialLinkText() { |
| var links = bot.locators.findElements({partialLinkText: 'a lin'}); |
| |
| assertEquals(5, links.length); |
| } |
| |
| function testShouldMatchFirstLinkWhenLinkTextIsTheEmptyString() { |
| var link = bot.locators.findElement({partialLinkText: ''}); |
| assertNotNull(link); |
| assertEquals('link', link.id); |
| } |
| |
| function testShouldFindEveryLinkWhenLinkTextIsTheEmptyString() { |
| var links = bot.locators.findElements({partialLinkText: ''}); |
| assertEquals(8, links.length); |
| } |
| |
| function testShouldBeAbleToFindElementByTagName() { |
| var link = bot.locators.findElement({tagName: 'A'}); |
| assertNotNull(link); |
| assertEquals('link', link.id); |
| } |
| |
| function testShouldBeAbleToFindElementsByTagName() { |
| var links = bot.locators.findElements({tagName: 'A'}); |
| assertEquals(8, links.length); |
| } |
| |
| function testCanAddANewElementLocatingStrategy() { |
| var expected = goog.dom.$('lion'); |
| bot.locators.add('fixed', { |
| single: function() { |
| return expected; |
| } |
| }); |
| |
| var seen = bot.locators.findElement({fixed: 'ignored'}); |
| |
| assertEquals(expected, seen); |
| } |
| |
| function testShouldSurviveObjectPrototypeBeingModified() { |
| Object.prototype.cheese = 'brie'; |
| Object.prototype.Inherits = function() { /* does nothing */ }; |
| |
| var first = bot.locators.findElement({name: 'tiger'}); |
| assertEquals('tiger', first.getAttribute('name')); |
| |
| var locator = new Object(); |
| locator.name = 'tiger'; |
| |
| var second = bot.locators.findElement(locator); |
| assertEquals('tiger', second.getAttribute('name')); |
| } |
| |
| function testShouldReturnNullIfXPathResolverThrowsNsError_Gecko() { |
| if (!goog.userAgent.GECKO) { |
| return; |
| } |
| |
| var stubs = new goog.testing.PropertyReplacer(); |
| // This simulates what happens in a firefox extension if the page |
| // reloads as an xpath query is being run. |
| stubs.set(document, 'createNSResolver', function() { |
| var error = new Error(); |
| error.name = 'NS_ERROR_ILLEGAL_VALUE'; |
| throw error; |
| }); |
| |
| try { |
| var result = bot.locators.findElement({xpath: '//body'}); |
| assertNull(result); |
| |
| var all = bot.locators.findElements({xpath: '//body'}); |
| assertEquals(0, all.length); |
| } finally { |
| stubs.reset(); |
| } |
| } |
| |
| </script> |
| </head> |
| <body> |
| <p id="x" name="para">Para</p> |
| |
| <div name="after" id="wrong" class="feline cats">nope</div> |
| <div name="right" id="after" class="dogs">yup</div> |
| <div name="lion" class="cats">simba</div> |
| <div name="tiger" class="cats">shere khan</div> |
| <div id="dotted_1" class="name.with.dots">dotted class</div> |
| <div id="dotted_2" class="name.with.dots">another dotted class</div> |
| |
| <form action="#"> |
| <input name="after" /><br /> |
| <input name="foo" /> |
| </form> |
| |
| <!-- This comment should be ignored --> |
| |
| <span name="foo">Furrfu</span> |
| |
| <ul> |
| <li id="illegal">item |
| <li id="illegal">item |
| <li id="illegal">item |
| <li id="illegal">item |
| </ul> |
| |
| <a id="link" href="#">this is a link</a> |
| <a name="fishsticks">this is a link</a> |
| <a href="#">this is a link</a> |
| <a href="#">this is a link</a> |
| <a href="#">this is a link</a> |
| |
| <a href="#">unrelated</a> |
| <a href="#" id="empty-link"></a> |
| <a href="#" id="comma-in-alt" alt="has, a comma">has, a comma</a> |
| |
| <iframe src="./testdata/iframe_page.html"></iframe> |
| </body> |
| </html> |