blob: 4b21a5e13f298619f8f7106a464ab4400d188b95 [file] [log] [blame]
<!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>