From 98215a603fb798cdb4178e49061977544aaa45b7 Mon Sep 17 00:00:00 2001 From: wei <> Date: Sat, 10 Dec 2005 11:49:29 +0000 Subject: Initial import selenium functional test framework. --- tests/FunctionalTests/selenium/selenium-api.js | 731 +++++++++++++++++++++++++ 1 file changed, 731 insertions(+) create mode 100644 tests/FunctionalTests/selenium/selenium-api.js (limited to 'tests/FunctionalTests/selenium/selenium-api.js') diff --git a/tests/FunctionalTests/selenium/selenium-api.js b/tests/FunctionalTests/selenium/selenium-api.js new file mode 100644 index 00000000..5d73e0fd --- /dev/null +++ b/tests/FunctionalTests/selenium/selenium-api.js @@ -0,0 +1,731 @@ +/* + * Copyright 2004 ThoughtWorks, 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. + * + */ + +storedVars = new Object(); + +function Selenium(browserbot) { + this.browserbot = browserbot; + this.optionLocatorFactory = new OptionLocatorFactory(); + this.page = function() { + return browserbot.getCurrentPage(); + }; +} + +Selenium.createForFrame = function(frame) { + return new Selenium(BrowserBot.createForFrame(frame)); +}; + +/* + * Reset the browserbot when an error occurs.. + */ +Selenium.prototype.reset = function() { + storedVars = new Object(); + this.browserbot.selectWindow("null"); +}; + +/* + * Click on the located element, and attach a callback to notify + * when the page is reloaded. + */ +Selenium.prototype.doModalDialogTest = function(returnValue) { + this.browserbot.doModalDialogTest(returnValue); +}; + +/* + * Click on the located element, and attach a callback to notify + * when the page is reloaded. + */ +Selenium.prototype.doClick = function(locator) { + var element = this.page().findElement(locator); + this.page().clickElement(element); +}; + +/** + * Overwrite the text in the located text element. + * TODO fail if it can't be typed into. + */ +Selenium.prototype.doType = function(locator, newText) { + var element = this.page().findElement(locator); + this.page().replaceText(element, newText); +}; + +Selenium.prototype.findToggleButton = function(locator) { + var element = this.page().findElement(locator); + if (element.checked == null) { + Assert.fail("Element " + locator + " is not a toggle-button."); + } + return element; +} + +/** + * Check a toggle-button. + */ +Selenium.prototype.doCheck = function(locator) { + this.findToggleButton(locator).checked = true; +}; + +/** + * Uncheck a toggle-button. + */ +Selenium.prototype.doUncheck = function(locator) { + this.findToggleButton(locator).checked = false; +}; + +/** + * Select the option from the located select element. + */ +Selenium.prototype.doSelect = function(locator, optionLocator) { + var element = this.page().findElement(locator); + if (!("options" in element)) { + throw new SeleniumError("Specified element is not a Select (has no options)"); + } + var locator = this.optionLocatorFactory.fromLocatorString(optionLocator); + var option = locator.findOption(element); + this.page().selectOption(element, option); +}; + +/* + * Open the browser to a new location. + */ +Selenium.prototype.doOpen = function(newLocation) { + this.browserbot.openLocation(newLocation); + return SELENIUM_PROCESS_WAIT; +}; + +/* + * Select the named window to be the active window. + */ +Selenium.prototype.doSelectWindow = function(windowName) { + this.browserbot.selectWindow(windowName); +}; + +/* + * Instruct Selenium to click Cancel on the next confirm dialog it encounters + */ +Selenium.prototype.doChooseCancelOnNextConfirmation = function() { + this.browserbot.cancelNextConfirmation(); +}; + +/* + * Instruct Selenium what to answear on the next prompt dialog it encounters + */ +Selenium.prototype.doAnswerOnNextPrompt = function(answer) { + this.browserbot.setNextPromptResult(answer); +}; + +/* + * Simulate the browser back button + */ +Selenium.prototype.doGoBack = function() { + this.page().goBack(); +}; + +/* + * Close the browser window or tab + */ +Selenium.prototype.doClose = function() { + this.page().close(); +}; + +/* + * Explicitly fire an event + */ +Selenium.prototype.doFireEvent = function(locator, event) { + var element = this.page().findElement(locator); + triggerEvent(element, event, false); +}; + +/* + * Get an alert message, or fail if there were no alerts. + */ +Selenium.prototype.getAlert = function() { + if (!this.browserbot.hasAlerts()) { + Assert.fail("There were no alerts"); + } + return this.browserbot.getNextAlert(); +}; + +/* + * Get a confirmation message, or fail if there were no confirmations. + */ +Selenium.prototype.getConfirmation = function() { + if (!this.browserbot.hasConfirmations()) { + Assert.fail("There were no confirmations"); + } + return this.browserbot.getNextConfirmation(); +}; + +/* + * Get a prompt message, or fail if there were no prompts. + */ +Selenium.prototype.getPrompt = function() { + if (! this.browserbot.hasPrompts()) { + Assert.fail("There were no prompts"); + } + return this.browserbot.getNextPrompt(); +}; + +/* + * Get the location of the current page. + */ +Selenium.prototype.getAbsoluteLocation = function() { + return this.page().location; +}; + +/* + * Verify the location of the current page ends with the expected location. + * If a querystring is provided, this is checked as well. + */ +Selenium.prototype.assertLocation = function(expectedLocation) { + var docLocation = this.page().location; + var searchPos = expectedLocation.lastIndexOf('?'); + + if (searchPos == -1) { + Assert.matches('*' + expectedLocation, docLocation.pathname); + } + else { + var expectedPath = expectedLocation.substring(0, searchPos); + Assert.matches('*' + expectedPath, docLocation.pathname); + + var expectedQueryString = expectedLocation.substring(searchPos); + Assert.equals(expectedQueryString, docLocation.search); + } +}; + +/* + * Get the title of the current page. + */ +Selenium.prototype.getTitle = function() { + return this.page().title(); +}; + + +/* + * Get the (trimmed) value of a form element. + * This is used to generate assertValue, verifyValue, ... + */ +Selenium.prototype.getValue = function(locator) { + var element = this.page().findElement(locator) + return getInputValue(element).trim(); +} + +/** + * Get the (trimmed) text of a form element. + * This is used to generate assertText, verifyText, ... + */ +Selenium.prototype.getText = function(locator) { + var element = this.page().findElement(locator); + return getText(element).trim(); +}; + +/** + * Assert that a toggle-button is checked. + */ +Selenium.prototype.assertChecked = function(locator) { + var element = this.page().findElement(locator); + if (element.checked == null) { + Assert.fail("Element " + locator + " is not a toggle-button."); + } + if (! element.checked) { + Assert.fail("Element " + locator + " is not checked."); + } +}; + +/** + * Assert that a toggle-button is NOT checked. + */ +Selenium.prototype.assertNotChecked = function(locator) { + var element = this.page().findElement(locator); + if (element.checked == null) { + Assert.fail("Element " + locator + " is not a toggle-button."); + } + if (element.checked) { + Assert.fail("Element " + locator + " is checked."); + } +}; + +/* + * Return the text for a single cell within an HTML table. + * The table locator syntax is table.row.column. + */ +Selenium.prototype.getTable = function(tableLocator) { + // This regular expression matches "tableName.row.column" + // For example, "mytable.3.4" + pattern = /(.*)\.(\d+)\.(\d+)/; + + if(!pattern.test(tableLocator)) { + throw new SeleniumError("Invalid target format. Correct format is tableName.rowNum.columnNum"); + } + + pieces = tableLocator.match(pattern); + + tableName = pieces[1]; + row = pieces[2]; + col = pieces[3]; + + var table = this.page().findElement(tableName); + if (row > table.rows.length) { + Assert.fail("Cannot access row " + row + " - table has " + table.rows.length + " rows"); + } + else if (col > table.rows[row].cells.length) { + Assert.fail("Cannot access column " + col + " - table row has " + table.rows[row].cells.length + " columns"); + } + else { + actualContent = getText(table.rows[row].cells[col]); + return actualContent.trim(); + } +}; + +/** + * Verify that the selected option satisfies the option locator. + */ +Selenium.prototype.assertSelected = function(target, optionLocator) { + var element = this.page().findElement(target); + var locator = this.optionLocatorFactory.fromLocatorString(optionLocator); + locator.assertSelected(element); +}; + +String.prototype.parseCSV = function() { + var values = this.replace(/\\,/g, "\n").split(","); + // Restore escaped commas + for (var i = 0; i < values.length; i++) { + values[i] = values[i].replace(/\n/g, ",").trim(); + } + return values; +}; + +/** + * Verify the label of all of the options in the drop=down. + */ +Selenium.prototype.assertSelectOptions = function(target, options) { + var element = this.page().findElement(target); + + var expectedOptionLabels = options.parseCSV(); + Assert.equals("Wrong number of options", expectedOptionLabels.length, element.options.length); + + for (var i = 0; i < element.options.length; i++) { + Assert.matches(expectedOptionLabels[i], element.options[i].text); + } +}; + +/** + * Get the value of an element attribute. The syntax for returning an element attribute + * is @attribute-name. Used to generate assert, verify, assertNot... + */ +Selenium.prototype.getAttribute = function(target) { + return this.page().findAttribute(target); +}; + +/* + * Asserts that the specified text is present in the page content. + */ +Selenium.prototype.assertTextPresent = function(expectedText) { + var allText = this.page().bodyText(); + + if(allText == "") { + Assert.fail("Page text not found"); + } else if(allText.indexOf(expectedText) == -1) { + Assert.fail("'" + expectedText + "' not found in page text."); + } +}; + +/* + * Asserts that the specified text is NOT present in the page content. + */ +Selenium.prototype.assertTextNotPresent = function(unexpectedText) { + var allText = this.page().bodyText(); + + if(allText == "") { + Assert.fail("Page text not found"); + } else if(allText.indexOf(unexpectedText) != -1) { + Assert.fail("'" + unexpectedText + "' was found in page text."); + } +}; + +/* + * Asserts that the specified element can be found. + */ +Selenium.prototype.assertElementPresent = function(locator) { + try { + this.page().findElement(locator); + } catch (e) { + Assert.fail("Element " + locator + " not found."); + } +}; + +/* + * Asserts that the specified element cannot be found. + */ +Selenium.prototype.assertElementNotPresent = function(locator) { + try { + this.page().findElement(locator); + } + catch (e) { + return; + } + Assert.fail("Element " + locator + " found."); +}; + +/* + * Asserts that the specified element is visible + */ +Selenium.prototype.assertVisible = function(locator) { + var element; + try { + element = this.page().findElement(locator); + } catch (e) { + Assert.fail("Element " + locator + " not present."); + } + if (! this.isVisible(element)) { + Assert.fail("Element " + locator + " not visible."); + } +}; + +/* + * Asserts that the specified element is visible + */ +Selenium.prototype.assertNotVisible = function(locator) { + var element; + try { + element = this.page().findElement(locator); + } catch (e) { + return; + } + if (this.isVisible(element)) { + Assert.fail("Element " + locator + " is visible."); + } +}; + +Selenium.prototype.isVisible = function(element) { + var visibility = this.getEffectiveStyleProperty(element, "visibility"); + var isDisplayed = this.isDisplayed(element); + return (visibility != "hidden" && isDisplayed); +}; + +Selenium.prototype.getEffectiveStyleProperty = function(element, property) { + var effectiveStyle = this.getEffectiveStyle(element); + var propertyValue = effectiveStyle[property]; + if (propertyValue == 'inherit' && element.parentNode.style) { + return this.getEffectiveStyleProperty(element.parentNode, property); + } + return propertyValue; +}; + +Selenium.prototype.isDisplayed = function(element) { + var display = this.getEffectiveStyleProperty(element, "display"); + if (display == "none") return false; + if (element.parentNode.style) { + return this.isDisplayed(element.parentNode); + } + return true; +}; + +Selenium.prototype.getEffectiveStyle = function(element) { + if (element.style == undefined) { + return undefined; // not a styled element + } + var window = this.browserbot.getContentWindow(); + if (window.getComputedStyle) { + // DOM-Level-2-CSS + return window.getComputedStyle(element, null); + } + if (element.currentStyle) { + // non-standard IE alternative + return element.currentStyle; + // TODO: this won't really work in a general sense, as + // currentStyle is not identical to getComputedStyle() + // ... but it's good enough for "visibility" + } + throw new SeleniumError("cannot determine effective stylesheet in this browser"); +}; + +/** + * Asserts that the specified element accepts user input visible + */ +Selenium.prototype.assertEditable = function(locator) { + var element = this.page().findElement(locator); + if (element.value == undefined) { + Assert.fail("Element " + locator + " is not an input."); + } + if (element.disabled) { + Assert.fail("Element " + locator + " is disabled."); + } +}; + +/** + * Asserts that the specified element does not accept user input + */ +Selenium.prototype.assertNotEditable = function(locator) { + var element = this.page().findElement(locator); + if (element.value == undefined) { + return; // not an input + } + if (element.disabled == false) { + Assert.fail("Element " + locator + " is editable."); + } +}; + + /* + * Return all buttons on the screen. + */ +Selenium.prototype.getAllButtons = function() { + return this.page().getAllButtons(); +}; + + /* + * Return all links on the screen. + */ +Selenium.prototype.getAllLinks = function() { + return this.page().getAllLinks(); +}; + + /* + * Return all fields on the screen. + */ +Selenium.prototype.getAllFields = function() { + return this.page().getAllFields(); +}; + +/* + * Set the context for the current Test + */ +Selenium.prototype.doContext = function(context) { + return this.page().setContext(context); +}; + +/* + * Store the value of a form input in a variable + */ +Selenium.prototype.doStoreValue = function(target, varName) { + if (!varName) { + // Backward compatibility mode: read the ENTIRE text of the page + // and stores it in a variable with the name of the target + value = this.page().bodyText(); + storedVars[target] = value; + return; + } + var element = this.page().findElement(target); + storedVars[varName] = getInputValue(element); +}; + +/* + * Store the text of an element in a variable + */ +Selenium.prototype.doStoreText = function(target, varName) { + var element = this.page().findElement(target); + storedVars[varName] = getText(element); +}; + +/* + * Store the value of an element attribute in a variable + */ +Selenium.prototype.doStoreAttribute = function(target, varName) { + storedVars[varName] = this.page().findAttribute(target); +}; + +/* + * Store the result of a literal value + */ +Selenium.prototype.doStore = function(value, varName) { + storedVars[varName] = value; +}; + + +/* + * Wait for the target to have the specified value by polling. + * The polling is done in TestLoop.kickoffNextCommandExecution() + */ +Selenium.prototype.doWaitForValue = function (target, value) { + var e = this.page().findElement(target); + testLoop.waitForCondition = function () { + return (e.value == value); + }; +}; + +/** + * Evaluate a parameter, performing javascript evaluation and variable substitution. + * If the string matches the pattern "javascript{ ... }", evaluate the string between the braces. + */ +Selenium.prototype.preprocessParameter = function(value) { + var match = value.match(/^javascript\{(.+)\}$/); + if (match && match[1]) { + return eval(match[1]).toString(); + } + return this.replaceVariables(value); +}; + +/* + * Search through str and replace all variable references ${varName} with their + * value in storedVars. + */ +Selenium.prototype.replaceVariables = function(str) { + var stringResult = str; + + // Find all of the matching variable references + var match = stringResult.match(/\$\{\w+\}/g); + if (!match) { + return stringResult; + } + + // For each match, lookup the variable value, and replace if found + for (var i = 0; match && i < match.length; i++) { + var variable = match[i]; // The replacement variable, with ${} + var name = variable.substring(2, variable.length - 1); // The replacement variable without ${} + var replacement = storedVars[name]; + if (replacement != undefined) { + stringResult = stringResult.replace(variable, replacement); + } + } + return stringResult; +}; + + +/** + * Factory for creating "Option Locators". + * An OptionLocator is an object for dealing with Select options (e.g. for + * finding a specified option, or asserting that the selected option of + * Select element matches some condition. + * The type of locator returned by the factory depends on the locator string: + * label= (OptionLocatorByLabel) + * value= (OptionLocatorByValue) + * index= (OptionLocatorByIndex) + * id= (OptionLocatorById) + * (default is OptionLocatorByLabel). + */ +function OptionLocatorFactory() { +} + +OptionLocatorFactory.prototype.fromLocatorString = function(locatorString) { + var locatorType = 'label'; + var locatorValue = locatorString; + // If there is a locator prefix, use the specified strategy + var result = locatorString.match(/^([a-zA-Z]+)=(.*)/); + if (result) { + locatorType = result[1]; + locatorValue = result[2]; + } + if (this.optionLocators == undefined) { + this.registerOptionLocators(); + } + if (this.optionLocators[locatorType]) { + return new this.optionLocators[locatorType](locatorValue); + } + throw new SeleniumError("Unkown option locator type: " + locatorType); +}; + +/** + * To allow for easy extension, all of the option locators are found by + * searching for all methods of OptionLocatorFactory.prototype that start + * with "OptionLocatorBy". + * TODO: Consider using the term "Option Specifier" instead of "Option Locator". + */ +OptionLocatorFactory.prototype.registerOptionLocators = function() { + this.optionLocators={}; + for (var functionName in this) { + var result = /OptionLocatorBy([A-Z].+)$/.exec(functionName); + if (result != null) { + var locatorName = result[1].lcfirst(); + this.optionLocators[locatorName] = this[functionName]; + } + } +}; + +/** + * OptionLocator for options identified by their labels. + */ +OptionLocatorFactory.prototype.OptionLocatorByLabel = function(label) { + this.label = label; + this.labelMatcher = new PatternMatcher(this.label); + this.findOption = function(element) { + for (var i = 0; i < element.options.length; i++) { + if (this.labelMatcher.matches(element.options[i].text)) { + return element.options[i]; + } + } + throw new SeleniumError("Option with label '" + this.label + "' not found"); + }; + + this.assertSelected = function(element) { + var selectedLabel = element.options[element.selectedIndex].text; + Assert.matches(this.label, selectedLabel); + }; +}; + +/** + * OptionLocator for options identified by their values. + */ +OptionLocatorFactory.prototype.OptionLocatorByValue = function(value) { + this.value = value; + this.valueMatcher = new PatternMatcher(this.value); + this.findOption = function(element) { + for (var i = 0; i < element.options.length; i++) { + if (this.valueMatcher.matches(element.options[i].value)) { + return element.options[i]; + } + } + throw new SeleniumError("Option with value '" + this.value + "' not found"); + }; + + this.assertSelected = function(element) { + var selectedValue = element.options[element.selectedIndex].value; + Assert.matches(this.value, selectedValue); + }; +}; + +/** + * OptionLocator for options identified by their index. + */ +OptionLocatorFactory.prototype.OptionLocatorByIndex = function(index) { + this.index = Number(index); + if (isNaN(this.index) || this.index < 0) { + throw new SeleniumError("Illegal Index: " + index); + } + + this.findOption = function(element) { + if (element.options.length <= this.index) { + throw new SeleniumError("Index out of range. Only " + element.options.length + " options available"); + } + return element.options[this.index]; + }; + + this.assertSelected = function(element) { + Assert.equals(this.index, element.selectedIndex); + }; +}; + +/** + * OptionLocator for options identified by their id. + */ +OptionLocatorFactory.prototype.OptionLocatorById = function(id) { + this.id = id; + this.idMatcher = new PatternMatcher(this.id); + this.findOption = function(element) { + for (var i = 0; i < element.options.length; i++) { + if (this.idMatcher.matches(element.options[i].id)) { + return element.options[i]; + } + } + throw new SeleniumError("Option with id '" + this.id + "' not found"); + }; + + this.assertSelected = function(element) { + var selectedId = element.options[element.selectedIndex].id; + Assert.matches(this.id, selectedId); + }; +}; + + -- cgit v1.2.3