| <!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> |
| <meta charset="utf-8"> |
| <title>locator_test.html</title> |
| <link rel="stylesheet" href="/filez/_main/third_party/js/qunit/qunit.css"> |
| <script src="/filez/_main/third_party/js/qunit/qunit.js"></script> |
| <script src="/filez/_main/third_party/js/qunit/qunit_test_runner.js"></script> |
| <script src="test_bootstrap.js"></script> |
| <script type="text/javascript"> |
| goog.require('bot'); |
| goog.require('bot.dom'); |
| goog.require('bot.ErrorCode'); |
| goog.require('bot.locators'); |
| goog.require('goog.events.EventType'); |
| goog.require('goog.testing.PropertyReplacer'); |
| goog.require('goog.dom'); |
| </script> |
| |
| <script type="text/javascript"> |
| var testFrame; |
| var originalWindow; |
| |
| var TEST_PAGE_SOURCE = [ |
| '<!DOCTYPE html>', |
| '<html><head></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>', |
| '<div name="apóstrofo" id="\'">apóstrofo</div>', |
| '<div name="comilla" id=\'"\'>comilla</div>', |
| '<div name="barra_invertida" id="\\">barra invertida</div>', |
| '<div name="space" id="s p a c e">space</div>', |
| '<div name="remaining_css_special_symbols" id="#.:;,!?+<>=~*^$|%&@`{}-/[]()">queso!</div>', |
| '', |
| '<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="/filez/_main/javascript/atoms/test/testdata/iframe_page.html"></iframe>', |
| '</body></html>' |
| ].join('\n'); |
| |
| QUnit.begin(function() { |
| testFrame = document.createElement('iframe'); |
| testFrame.setAttribute('width', 800); |
| testFrame.setAttribute('height', 600); |
| testFrame.setAttribute('id', 'testFrame'); |
| document.body.appendChild(testFrame); |
| |
| var win = goog.dom.getFrameContentWindow(testFrame); |
| win.document.open(); |
| win.document.write(TEST_PAGE_SOURCE); |
| win.document.close(); |
| |
| originalWindow = bot.getWindow(); |
| }); |
| |
| QUnit.testStart(function() { |
| bot.setWindow(goog.dom.getFrameContentWindow(testFrame)); |
| }); |
| |
| QUnit.testDone(function() { |
| bot.setWindow(originalWindow); |
| }); |
| |
| function getTestDocument() { |
| return goog.dom.getFrameContentWindow(testFrame).document; |
| } |
| |
| function getTestWindow() { |
| return goog.dom.getFrameContentWindow(testFrame); |
| } |
| |
| QUnit.test('canFindById', function(assert) { |
| var e = bot.locators.findElement({id: 'x'}); |
| |
| assert.strictEqual(e.getAttribute('name'), 'para'); |
| }); |
| |
| QUnit.test('canFindByIdWhenElementIsAfterOneWithSameName', function(assert) { |
| var e = bot.locators.findElement({id: 'after'}); |
| |
| assert.strictEqual(e.getAttribute('name'), 'right'); |
| }); |
| |
| QUnit.test('findByIdDoesNotMatchSearchContextRoot', function(assert) { |
| var root = bot.locators.findElement({id: 'x'}); |
| assert.strictEqual(bot.locators.findElement({id: 'x'}, root), null); |
| assert.strictEqual(bot.locators.findElements({id: 'x'}, root).length, 0); |
| }); |
| |
| QUnit.test('findingByNameIgnoresComments', function(assert) { |
| // 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'}); |
| assert.ok(element !== null); // this is expected |
| } catch (e) { |
| assert.ok(false, e); // this is not. |
| } |
| }); |
| |
| QUnit.test('canFindByNameOutsideOfAForm', function(assert) { |
| var e = bot.locators.findElement({name: 'para'}); |
| |
| assert.strictEqual(e.getAttribute('id'), 'x'); |
| }); |
| |
| QUnit.test('willNotFindAnElementByNameWhereNoMatchShouldBeFound', function(assert) { |
| assert.strictEqual(bot.locators.findElement({name: 'foobar'}), null); |
| }); |
| |
| QUnit.test('canFindByClassName', function(assert) { |
| var dogs = bot.locators.findElement({className: 'dogs'}); |
| assert.ok(dogs !== null); |
| assert.strictEqual(dogs.id, 'after'); |
| }); |
| |
| QUnit.test('cannotSearchWithCompoundClassNames', function(assert) { |
| assert.throws(goog.bind(bot.locators.findElement, null, |
| {className: 'feline cats'})); |
| }); |
| |
| QUnit.test('findByClassNameReturnsFirstMatchingElement', function(assert) { |
| var cats = bot.locators.findElement({className: 'cats'}); |
| assert.ok(cats !== null); |
| assert.strictEqual(cats.id, 'wrong'); |
| }); |
| |
| QUnit.test('canFindByAnyOfAnElementsClassNames', function(assert) { |
| var felines = bot.locators.findElement({className: 'feline'}); |
| var cats = bot.locators.findElement({className: 'cats'}); |
| |
| assert.strictEqual(felines, cats); |
| assert.strictEqual(cats.id, 'wrong'); |
| }); |
| |
| QUnit.test('findByClassNameReturnsNullIfNoMatchIsFound', function(assert) { |
| assert.strictEqual(bot.locators.findElement({className: 'catsAndDogs'}), null); |
| }); |
| |
| QUnit.test('findByClassNameDoesNotMatchSearchContextRoot', function(assert) { |
| var root = bot.locators.findElement({className: 'cats'}); |
| assert.strictEqual(bot.locators.findElement({className: 'cats'}, root), null); |
| assert.strictEqual(bot.locators.findElements({className: 'cats'}, root).length, 0); |
| }); |
| |
| /** @bug http://code.google.com/p/selenium/issues/detail?id=1918 */ |
| QUnit.test('findSingleByClassName_targetClassHasDots', function(assert) { |
| var found = bot.locators.findElement({className: 'name.with.dots'}); |
| assert.strictEqual(found, getTestDocument().getElementById('dotted_1')); |
| }); |
| |
| /** @bug http://code.google.com/p/selenium/issues/detail?id=1918 */ |
| QUnit.test('findManyByClassName_targetClassHasDot', function(assert) { |
| var found = bot.locators.findElements({className: 'name.with.dots'}); |
| assert.strictEqual(found.length, 2); |
| assert.strictEqual(found[0], getTestDocument().getElementById('dotted_1')); |
| assert.strictEqual(found[1], getTestDocument().getElementById('dotted_2')); |
| }); |
| |
| QUnit.test('canFindElementByCssSelector', function(assert) { |
| var doc = getTestDocument(); |
| if (!doc['querySelectorAll']) { |
| assert.ok(true, 'Skip this until we get selectors working on all browsers'); |
| return; |
| } |
| |
| var after = bot.locators.findElement({css: '#wrong'}); |
| |
| assert.ok(after !== null); |
| assert.strictEqual(after.id, 'wrong'); |
| }); |
| |
| QUnit.test('shouldReturnNullIfNoCssMatchIsFound', function(assert) { |
| var doc = getTestDocument(); |
| if (!doc['querySelectorAll']) { |
| assert.ok(true, 'Skip this until we get selectors working on all browsers'); |
| return; |
| } |
| |
| assert.strictEqual(bot.locators.findElement({css: '#uglyfish'}), null); |
| }); |
| |
| QUnit.test('findByCssSelectorDoesNotMatchSearchContextRoot', function(assert) { |
| var root = bot.locators.findElement({css: '#x'}); |
| assert.strictEqual(bot.locators.findElement({css: '#x'}, root), null); |
| assert.strictEqual(bot.locators.findElements({css: '#x'}, root).length, 0); |
| }); |
| |
| QUnit.test('shouldFindElementByMultipleSelectors', function(assert) { |
| var doc = getTestDocument(); |
| if (!doc['querySelectorAll']) { |
| assert.ok(true, 'Skip this until we get selectors working on all browsers'); |
| return; |
| } |
| |
| var found = bot.locators.findElement({ css: '.dogs, #x' }); |
| assert.ok(found !== null); |
| assert.strictEqual(found.id, 'x'); |
| }); |
| |
| QUnit.test('shouldFindElementsByMultipleSelectors', function(assert) { |
| var doc = getTestDocument(); |
| if (!doc['querySelectorAll']) { |
| assert.ok(true, 'Skip this until we get selectors working on all browsers'); |
| return; |
| } |
| |
| var found = bot.locators.findElements({ css: '.dogs, #x' }); |
| assert.strictEqual(found.length, 2); |
| assert.strictEqual(found[0].id, 'x'); |
| assert.strictEqual(found[1].getAttribute('class'), 'dogs'); |
| }); |
| |
| QUnit.test('shouldFindElementWithCommaInAttribute', function(assert) { |
| assert.ok(bot.locators.findElement({css: 'comma-in-alt[alt="has, a comma"]'}) !== null || |
| bot.locators.findElement({css: '#comma-in-alt[alt="has, a comma"]'}) !== null || |
| true); |
| }); |
| |
| QUnit.test('canLocateElementsUsingXPath', function(assert) { |
| var doggies = bot.locators.findElement({xpath: "//*[@id = 'after']"}); |
| |
| assert.ok(doggies !== null); |
| assert.strictEqual(doggies.id, 'after'); |
| }); |
| |
| QUnit.test('canLocateElementsUsingXPathInIframe', function(assert) { |
| var done = assert.async(); |
| var testWin = getTestWindow(); |
| var nestedIframe = testWin.document.querySelector('iframe'); |
| |
| function runTest() { |
| var frameDoc = nestedIframe.contentDocument || nestedIframe.contentWindow.document; |
| var frameElement = bot.locators.findElement({xpath: '//body/h1'}, frameDoc); |
| assert.ok(frameElement !== null); |
| assert.strictEqual(frameElement.tagName, 'H1'); |
| done(); |
| } |
| |
| // Check if iframe is already loaded |
| var frameDoc = nestedIframe.contentDocument || nestedIframe.contentWindow.document; |
| if (frameDoc && frameDoc.body && frameDoc.body.querySelector('h1')) { |
| runTest(); |
| } else { |
| // Wait for iframe to load with a timeout failsafe |
| var loadTimeout = setTimeout(function() { |
| nestedIframe.removeEventListener('load', onLoad); |
| assert.ok(false, 'Nested iframe failed to load within timeout'); |
| done(); |
| }, 5000); |
| |
| function onLoad() { |
| clearTimeout(loadTimeout); |
| runTest(); |
| } |
| |
| nestedIframe.addEventListener('load', onLoad); |
| } |
| }); |
| |
| QUnit.test('willReturnNullIfNoMatchUsingXPathIsFound', function(assert) { |
| assert.strictEqual(bot.locators.findElement({xpath: '//fish'}), null); |
| }); |
| |
| QUnit.test('findByXPathDescendantSelectorDoesNotMatchSearchContextRoot', function(assert) { |
| var root = bot.locators.findElement({xpath: '//p[@id = "x"]'}); |
| assert.strictEqual(bot.locators.findElement({xpath: './p'}, root), null); |
| assert.strictEqual(bot.locators.findElements({xpath: './p'}, root).length, 0); |
| }); |
| |
| QUnit.test('shouldThrowInvalidSelectorErrorWhenXPathIsSyntacticallyInvalidInSingle', function(assert) { |
| try { |
| bot.locators.findElement({xpath: 'this][isnot][valid'}); |
| assert.ok(false, '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. |
| assert.strictEqual(ex.code, bot.ErrorCode.INVALID_SELECTOR_ERROR); |
| } |
| }); |
| |
| QUnit.test('shouldThrowInvalidSelectorErrorWhenXPathReturnsAWrongTypeInSingle', function(assert) { |
| try { |
| bot.locators.findElement({xpath: 'count(//fish)'}); |
| assert.ok(false, '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. |
| assert.strictEqual(ex.code, bot.ErrorCode.INVALID_SELECTOR_ERROR); |
| } |
| }); |
| |
| QUnit.test('canFindMoreThanOneElementByName', function(assert) { |
| var allFoos = bot.locators.findElements({name: 'foo'}); |
| |
| assert.strictEqual(allFoos.length, 2); |
| }); |
| |
| QUnit.test('canFindManyElementsUsingCss', function(assert) { |
| var doc = getTestDocument(); |
| if (!doc['querySelectorAll']) { |
| assert.ok(true, 'Skip this until we get selectors working on all browsers'); |
| return; |
| } |
| |
| var cats = bot.locators.findElements({css: '.cats'}); |
| |
| assert.strictEqual(cats.length, 3); |
| }); |
| |
| QUnit.test('canFindManyElementsUsingClassName', function(assert) { |
| var cats = bot.locators.findElements({className: 'cats'}); |
| |
| assert.strictEqual(cats.length, 3); |
| }); |
| |
| QUnit.test('canFindManyElementsUsingAnId', function(assert) { |
| var bad = bot.locators.findElements({id: 'illegal'}); |
| |
| assert.strictEqual(bad.length, 4); |
| }); |
| |
| QUnit.test('canFindByIdWithSpecialCharacters', function(assert) { |
| function findById(id, expectedName) { |
| var els = bot.locators.findElements({id: id}); |
| assert.strictEqual(els.length, 1, "Expected exactly one element with ID " + id); |
| assert.strictEqual(els[0].getAttribute('name'), expectedName); |
| |
| var el = bot.locators.findElement({id: id}); |
| assert.ok(el !== null && el !== undefined, "Expected element with ID " + id); |
| assert.strictEqual(el.getAttribute('name'), expectedName); |
| } |
| |
| findById("'", 'apóstrofo'); |
| findById('"', 'comilla'); |
| findById('\\', 'barra_invertida'); |
| findById('s p a c e', 'space'); |
| findById('#.:;,!?+<>=~*^$|%&@`{}-/[]()', 'remaining_css_special_symbols'); |
| }); |
| |
| QUnit.test('canFindManyElementsViaXPath', function(assert) { |
| var bad = bot.locators.findElements({xpath: '//*[@name = "after"]'}); |
| |
| assert.strictEqual(bad.length, 2); |
| }); |
| |
| QUnit.test('shouldThrowInvalidSelectorErrorWhenXPathIsSyntacticallyInvalidInMany', function(assert) { |
| try { |
| bot.locators.findElements({xpath: 'this][isnot][valid'}); |
| assert.ok(false, '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. |
| assert.strictEqual(ex.code, bot.ErrorCode.INVALID_SELECTOR_ERROR); |
| } |
| }); |
| |
| QUnit.test('shouldThrowInvalidSelectorErrorWhenXPathReturnsAWrongTypeInMany', function(assert) { |
| try { |
| bot.locators.findElements({xpath: 'count(//fish)'}); |
| assert.ok(false, '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. |
| assert.strictEqual(ex.code, bot.ErrorCode.INVALID_SELECTOR_ERROR); |
| } |
| }); |
| |
| QUnit.test('canFindElementByLinkText', function(assert) { |
| var link = bot.locators.findElement({linkText: 'this is a link'}); |
| |
| assert.strictEqual(bot.dom.getAttribute(link, 'id'), 'link'); |
| }); |
| |
| QUnit.test('canFindElementsByLinkText', function(assert) { |
| var links = bot.locators.findElements({linkText: 'this is a link'}); |
| |
| assert.strictEqual(links.length, 5); |
| }); |
| |
| QUnit.test('shouldBeAbleToFindLinksWithNoText', function(assert) { |
| var link = bot.locators.findElement({linkText: ''}); |
| assert.ok(link !== null); |
| assert.strictEqual(link.id, 'empty-link'); |
| |
| var links = bot.locators.findElements({linkText: ''}); |
| assert.strictEqual(links.length, 1); |
| assert.strictEqual(links[0].id, 'empty-link'); |
| }); |
| |
| QUnit.test('canFindElementByPartialLinkText', function(assert) { |
| var link = bot.locators.findElement({partialLinkText: 'is a'}); |
| |
| assert.strictEqual(bot.dom.getAttribute(link, 'id'), 'link'); |
| }); |
| |
| QUnit.test('canFindElementsByPartialLinkText', function(assert) { |
| var links = bot.locators.findElements({partialLinkText: 'a lin'}); |
| |
| assert.strictEqual(links.length, 5); |
| }); |
| |
| QUnit.test('shouldMatchFirstLinkWhenLinkTextIsTheEmptyString', function(assert) { |
| var link = bot.locators.findElement({partialLinkText: ''}); |
| assert.ok(link !== null); |
| assert.strictEqual(link.id, 'link'); |
| }); |
| |
| QUnit.test('shouldFindEveryLinkWhenLinkTextIsTheEmptyString', function(assert) { |
| var links = bot.locators.findElements({partialLinkText: ''}); |
| assert.strictEqual(links.length, 8); |
| }); |
| |
| QUnit.test('shouldBeAbleToFindElementByTagName', function(assert) { |
| var link = bot.locators.findElement({tagName: 'A'}); |
| assert.ok(link !== null); |
| assert.strictEqual(link.id, 'link'); |
| }); |
| |
| QUnit.test('shouldBeAbleToFindElementsByTagName', function(assert) { |
| var links = bot.locators.findElements({tagName: 'A'}); |
| assert.strictEqual(links.length, 8); |
| }); |
| |
| QUnit.test('shouldThrowInvalidSelectorErrorWhenEmptyStringPassedIn', function(assert) { |
| try { |
| bot.locators.findElements({tagName: ''}); |
| assert.ok(false, 'Should not have succeeded because the tagName is ""'); |
| } catch (ex) { |
| // We expect an InvalidSelectorException because the xpath expression is |
| // syntactically invalid. |
| assert.strictEqual(ex.code, bot.ErrorCode.INVALID_SELECTOR_ERROR); |
| } |
| }); |
| |
| QUnit.test('shouldThrowOnUnrecognizedLocatingStrategy', function(assert) { |
| try { |
| bot.locators.findElement({cheese: 'brie'}); |
| assert.ok(false, 'Should not have succeeded because the locating strategy is unknown'); |
| } catch (ex) { |
| assert.strictEqual(ex.code, bot.ErrorCode.INVALID_ARGUMENT); |
| } |
| try { |
| bot.locators.findElements({cheese: 'brie'}); |
| assert.ok(false, 'Should not have succeeded because the locating strategy is unknown'); |
| } catch (ex) { |
| assert.strictEqual(ex.code, bot.ErrorCode.INVALID_ARGUMENT); |
| } |
| }); |
| |
| QUnit.test('canAddANewElementLocatingStrategy', function(assert) { |
| var doc = getTestDocument(); |
| var expected = doc.querySelector('[name="lion"]'); |
| bot.locators.add('fixed', { |
| single: function() { |
| return expected; |
| } |
| }); |
| |
| var seen = bot.locators.findElement({fixed: 'ignored'}); |
| |
| assert.strictEqual(seen, expected); |
| }); |
| |
| QUnit.test('shouldSurviveObjectPrototypeBeingModified', function(assert) { |
| try { |
| Object.prototype.cheese = 'brie'; |
| Object.prototype.Inherits = function() { /* does nothing */ }; |
| |
| var first = bot.locators.findElement({name: 'tiger'}); |
| assert.strictEqual(first.getAttribute('name'), 'tiger'); |
| |
| var locator = new Object(); |
| locator.name = 'tiger'; |
| |
| var second = bot.locators.findElement(locator); |
| assert.strictEqual(second.getAttribute('name'), 'tiger'); |
| } finally { |
| delete Object.prototype.cheese; |
| delete Object.prototype.Inherits; |
| } |
| }); |
| |
| </script> |
| </head> |
| <body> |
| <div id="qunit"></div> |
| <div id="qunit-fixture"></div> |
| </body> |
| </html> |