blob: f0b718a991136fc877f4e0a52ee1f8f35e9ad97d [file] [log] [blame]
// Copyright 2012 Selenium committers
// Copyright 2012 Software Freedom Conservancy
//
// 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.
/**
* @fileoverview Command handlers used by the SafariDriver's injected script.
*/
goog.provide('safaridriver.inject.commands');
goog.require('bot');
goog.require('bot.Error');
goog.require('bot.ErrorCode');
goog.require('bot.action');
goog.require('bot.dom');
goog.require('bot.frame');
goog.require('bot.inject');
goog.require('bot.inject.cache');
goog.require('bot.locators');
goog.require('bot.window');
goog.require('goog.array');
goog.require('goog.debug.Logger');
goog.require('goog.math.Coordinate');
goog.require('goog.math.Size');
goog.require('goog.net.cookies');
goog.require('goog.style');
goog.require('safaridriver.inject.message.Activate');
goog.require('webdriver.atoms.element');
/**
* @type {!goog.debug.Logger}
* @const
* @private
*/
safaridriver.inject.commands.LOG_ = goog.debug.Logger.getLogger(
'safaridriver.inject.commands');
/** @return {string} The name of the current window. */
safaridriver.inject.commands.getWindowName = function() {
return window.name;
};
/** @return {string} The current URL. */
safaridriver.inject.commands.getCurrentUrl = function() {
return window.location.href;
};
/**
* Loads a new URL in the current page.
* @param {!safaridriver.Command} command The command object.
*/
safaridriver.inject.commands.loadUrl = function(command) {
window.location.href = /** @type {string} */ (command.getParameter('url'));
// No need to send a response. The global page should be listening for the
// navigate event.
};
/** Reloads the current page. */
safaridriver.inject.commands.reloadPage = function() {
window.location.reload();
// No need to send a response. The global page should be listening for the
// navigate event.
};
/**
* Stub that reports an error that navigating through the browser history does
* not work for the SafariDriver.
*/
safaridriver.inject.commands.unsupportedHistoryNavigation = function() {
throw Error('Yikes! Safari history navigation does not work. We can ' +
'go forward or back, but once we do, we can no longer ' +
'communicate with the page...');
};
/** @return {string} The document title. */
safaridriver.inject.commands.getTitle = function() {
return document.title;
};
/** @return {string} A string representation of the current page source. */
safaridriver.inject.commands.getPageSource = function() {
return new XMLSerializer().serializeToString(document);
};
/**
* Defines an element locating command.
* @param {function(!Object, (Document|Element)=):
* (Element|!goog.array.ArrayLike.<Element>)} locatorFn The locator function
* that should be used.
* @return {function(!safaridriver.Command): !bot.response.ResponseObject} The
* locator command function.
* @private
*/
safaridriver.inject.commands.findElementCommand_ = function(locatorFn) {
return function(command) {
var locator = {};
locator[command.getParameter('using')] = command.getParameter('value');
var args = [locator];
if (command.getParameter('id')) {
args.push({'ELEMENT': command.getParameter('id')});
}
return bot.inject.executeScript(locatorFn, args);
};
};
/**
* Locates an element on the page.
* @param {!safaridriver.Command} command The command object.
* @return {!bot.response.ResponseObject} The command response.
*/
safaridriver.inject.commands.findElement =
safaridriver.inject.commands.findElementCommand_(bot.locators.findElement);
/**
* Locates multiple elements on the page.
* @param {!safaridriver.Command} command The command object.
* @return {bot.response.ResponseObject} The command response.
*/
safaridriver.inject.commands.findElements =
safaridriver.inject.commands.findElementCommand_(bot.locators.findElements);
/**
* Retrieves the element that currently has focus.
* @return {!bot.response.ResponseObject} The response object.
*/
safaridriver.inject.commands.getActiveElement = function() {
var getActiveElement = goog.partial(bot.dom.getActiveElement, document);
return /** @type {!bot.response.ResponseObject} */ (bot.inject.executeScript(
getActiveElement, []));
};
/**
* Adds a new cookie to the page.
* @param {!safaridriver.Command} command The command object.
*/
safaridriver.inject.commands.addCookie = function(command) {
var cookie = command.getParameter('cookie');
// The WebDriver wire protocol defines cookie expiration times in seconds
// since midnight, January 1, 1970 UTC, but goog.net.Cookies expects them
// to be in seconds since "right now".
var maxAge = cookie['expiry'];
if (goog.isNumber(maxAge)) {
maxAge = new Date(maxAge) - goog.now();
}
// TODO: check whether cookie['domain'] is valid.
goog.net.cookies.set(cookie['name'], cookie['value'], maxAge,
cookie['path'], cookie['domain'], cookie['secure']);
};
/**
* @return {!Array.<{name:string, value:string}>} A list of the cookies visible
* to the current page.
*/
safaridriver.inject.commands.getCookies = function() {
var keys = goog.net.cookies.getKeys();
return goog.array.map(keys, function(key) {
return {
'name': key,
'value': goog.net.cookies.get(key)
};
});
};
/** Deletes all cookies visible to the current page. */
safaridriver.inject.commands.deleteCookies = function() {
goog.net.cookies.clear();
};
/**
* Deletes a specified cookie.
* @param {!safaridriver.Command} command The command object.
*/
safaridriver.inject.commands.deleteCookie = function(command) {
goog.net.cookies.remove(/** @type {string} */ (command.getParameter('name')));
};
/**
* Ensures the provided command's element is encoded as a WebElement JSON
* object, as defined by the WebDriver wire protocol.
* @param {!safaridriver.Command} command The command to modify.
* @return {!safaridriver.Command} The modified command.
* @private
*/
safaridriver.inject.commands.prepareElementCommand_ = function(command) {
var element = command.getParameter('id');
if (goog.isDef(element) && !goog.isObject(element)) {
command.setParameter('id', {
'ELEMENT': element
});
}
return command;
};
/**
* Creates a command that targets a specific DOM element.
* @param {!Function} handlerFn The actual handler function. The first parameter
* should be the Element to target.
* @param {...string} var_args Any named parameters which should be extracted
* and passed as arguments to {@code commandFn}.
* @return {function(!safaridriver.Command)} The new element command function.
* @private
*/
safaridriver.inject.commands.elementCommand_ = function(handlerFn, var_args) {
var keys = goog.array.slice(arguments, 1);
return function(command) {
command = safaridriver.inject.commands.prepareElementCommand_(command);
var element = command.getParameter('id');
var args = goog.array.concat(element, goog.array.map(keys, function(key) {
return command.getParameter(key);
}));
return bot.inject.executeScript(handlerFn, args);
};
};
/**
* @param {!safaridriver.Command} command The command to execute.
* @see bot.action.clear
*/
safaridriver.inject.commands.clearElement =
safaridriver.inject.commands.elementCommand_(bot.action.clear);
/**
* @param {!safaridriver.Command} command The command to execute.
* @see bot.action.click
*/
safaridriver.inject.commands.clickElement =
safaridriver.inject.commands.elementCommand_(bot.action.click);
/**
* @param {!safaridriver.Command} command The command to execute.
* @see bot.action.submit
*/
safaridriver.inject.commands.submitElement =
safaridriver.inject.commands.elementCommand_(bot.action.submit);
/**
* @param {!safaridriver.Command} command The command to execute.
* @see webdriver.atoms.element.getAttribute
*/
safaridriver.inject.commands.getElementAttribute =
safaridriver.inject.commands.elementCommand_(
webdriver.atoms.element.getAttribute, 'name');
/**
* @param {!safaridriver.Command} command The command to execute.
* @see goog.style.getPageOffset
*/
safaridriver.inject.commands.getElementLocation =
safaridriver.inject.commands.elementCommand_(goog.style.getPageOffset);
/**
* @param {!safaridriver.Command} command The command to execute.
* @see bot.dom.getLocationInView
*/
safaridriver.inject.commands.getLocationInView =
safaridriver.inject.commands.elementCommand_(bot.dom.getLocationInView);
/**
* @param {!safaridriver.Command} command The command to execute.
* @see goog.style.getSize
*/
safaridriver.inject.commands.getElementSize =
safaridriver.inject.commands.elementCommand_(goog.style.getSize);
/**
* @param {!safaridriver.Command} command The command to execute.
* @see webdriver.atoms.element.getText
*/
safaridriver.inject.commands.getElementText =
safaridriver.inject.commands.elementCommand_(
webdriver.atoms.element.getText);
/**
* @param {!safaridriver.Command} command The command to execute.
*/
safaridriver.inject.commands.getElementTagName =
safaridriver.inject.commands.elementCommand_(function(el) {
return el.tagName;
});
/**
* @param {!safaridriver.Command} command The command to execute.
* @see bot.dom.isShown
*/
safaridriver.inject.commands.isElementDisplayed =
safaridriver.inject.commands.elementCommand_(bot.dom.isShown);
/**
* @param {!safaridriver.Command} command The command to execute.
* @see bot.dom.isEnabled
*/
safaridriver.inject.commands.isElementEnabled =
safaridriver.inject.commands.elementCommand_(bot.dom.isEnabled);
/**
* @param {!safaridriver.Command} command The command to execute.
* @see webdriver.atoms.element.isSelected
*/
safaridriver.inject.commands.isElementSelected =
safaridriver.inject.commands.elementCommand_(
webdriver.atoms.element.isSelected);
/**
* @param {!safaridriver.Command} command The command to execute.
*/
safaridriver.inject.commands.elementEquals =
safaridriver.inject.commands.elementCommand_(function(a, b) {
return a === b;
}, 'other');
/**
* @param {!safaridriver.Command} command The command to execute.
* @see bot.dom.getEffectiveStyle
*/
safaridriver.inject.commands.getCssValue =
safaridriver.inject.commands.elementCommand_(bot.dom.getEffectiveStyle,
'propertyName');
/**
* @return {!goog.math.Coordinate} The position of the window.
* @see bot.window.getPosition
*/
safaridriver.inject.commands.getWindowPosition = function() {
return bot.window.getPosition();
};
/**
* @param {!safaridriver.Command} command The command to execute.
* @see bot.window.setPosition
*/
safaridriver.inject.commands.setWindowPosition = function(command) {
var position = new goog.math.Coordinate(
/** @type {number} */ (command.getParameter('x')),
/** @type {number} */ (command.getParameter('y')));
bot.window.setPosition(position);
};
/**
* @return {!goog.math.Size} The size of the window.
* @see bot.window.getSize
*/
safaridriver.inject.commands.getWindowSize = function() {
return bot.window.getSize();
};
/**
* @param {!safaridriver.Command} command The command to execute.
* @see bot.window.setSize
*/
safaridriver.inject.commands.setWindowSize = function(command) {
var size = new goog.math.Size(
/** @type {number} */ (command.getParameter('width')),
/** @type {number} */ (command.getParameter('height')));
bot.window.setSize(size);
};
/** Maximizes the window. */
safaridriver.inject.commands.maximizeWindow = function() {
window.moveTo(0, 0);
window.resizeTo(window.screen.width, window.screen.height);
};
/**
* Executes a command in the context of the current page.
* @param {!safaridriver.Command} command The command to execute.
* @param {!safaridriver.inject.Tab} tab A reference to the tab issuing this
* command.
* @return {!webdriver.promise.Promise} A promise that will be resolved with the
* {@link bot.response.ResponseObject} from the page.
* @throws {Error} If there is an error while sending the command to the page.
*/
safaridriver.inject.commands.executeInPage = function(command, tab) {
command = safaridriver.inject.commands.prepareElementCommand_(command);
return tab.executeInPage(command);
};
/**
* Locates a frame and sends a message to it to activate itself with the
* extension. The located frame will be
* @param {!safaridriver.Command} command The command to execute.
* the target of all subsequent commands.
* @throws {Error} If there is an error whilst locating the frame.
*/
safaridriver.inject.commands.switchToFrame = function(command) {
var id = command.getParameter('id');
var frameWindow;
if (goog.isNull(id)) {
safaridriver.inject.commands.LOG_.info('Resetting focus to window.top');
frameWindow = window.top;
} else if (goog.isString(id)) {
safaridriver.inject.commands.LOG_.info(
'Switching to frame by name or ID: ' + id);
frameWindow = bot.frame.findFrameByNameOrId(/** @type {string} */ (id));
} else if (goog.isNumber(id)) {
safaridriver.inject.commands.LOG_.info(
'Switching to frame by index: ' + id);
frameWindow = bot.frame.findFrameByIndex(/** @type {number} */ (id));
} else {
var elementKey = /** @type {string} */ (id[bot.inject.ELEMENT_KEY]);
safaridriver.inject.commands.LOG_.info('Switching to frame by ' +
'WebElement: ' + elementKey);
// ID must be a WebElement. Pull it from the cache.
var frameElement = bot.inject.cache.getElement(elementKey);
frameWindow = bot.frame.getFrameWindow(
/** @type {!(HTMLIFrameElement|HTMLFrameElement)} */ (frameElement));
}
if (!frameWindow) {
throw new bot.Error(bot.ErrorCode.NO_SUCH_FRAME,
'Unable to locate frame with ' + id);
}
// De-activate ourselves. We should no longer respond to commands until
// we are re-activated.
safaridriver.inject.Tab.getInstance().setActive(false);
var message = new safaridriver.inject.message.Activate(command);
message.send(frameWindow);
};