UNPKG

slimerjs-firefox

Version:

This repo includes slimerjs as well as downloads a local copy of Firefox.

897 lines (786 loc) 38.3 kB
/* This file is part of the GhostDriver by Ivan De Marino <http://ivandemarino.me>. Copyright (c) 2014, Ivan De Marino <http://ivandemarino.me> Copyright (c) 2014, Alex Anderson <@alxndrsn> All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ var ghostdriver = ghostdriver || {}; ghostdriver.SessionReqHand = function(session) { // private: const _const = { URL : "url", ELEMENT : "element", ELEMENTS : "elements", ELEMENT_DIR : "/element/", ACTIVE : "active", TITLE : "title", WINDOW : "window", CURRENT : "current", SIZE : "size", POSITION : "position", MAXIMIZE : "maximize", FORWARD : "forward", BACK : "back", REFRESH : "refresh", EXECUTE : "execute", EXECUTE_ASYNC : "execute_async", SCREENSHOT : "screenshot", TIMEOUTS : "timeouts", TIMEOUTS_DIR : "/timeouts/", ASYNC_SCRIPT : "async_script", IMPLICIT_WAIT : "implicit_wait", WINDOW_HANDLE : "window_handle", WINDOW_HANDLES : "window_handles", FRAME : "frame", SOURCE : "source", COOKIE : "cookie", KEYS : "keys", MOVE_TO : "moveto", CLICK : "click", BUTTON_DOWN : "buttondown", BUTTON_UP : "buttonup", DOUBLE_CLICK : "doubleclick", PHANTOM_DIR : "/phantom/", PHANTOM_EXEC : "execute", LOG : "log", TYPES : "types" }; var _session = session, _protoParent = ghostdriver.SessionReqHand.prototype, _locator = new ghostdriver.WebElementLocator(session), _errors = _protoParent.errors, _log = ghostdriver.logger.create("SessionReqHand"), _handle = function(req, res) { var element; _protoParent.handle.call(this, req, res); // Handle "/url" GET and POST if (req.urlParsed.file === _const.URL) { //< ".../url" if (req.method === "GET") { _getUrlCommand(req, res); } else if (req.method === "POST") { _postUrlCommand(req, res); } return; } else if (req.urlParsed.file === _const.SCREENSHOT && req.method === "GET") { _getScreenshotCommand(req, res); return; } else if (req.urlParsed.file === _const.WINDOW) { //< ".../window" if (req.method === "DELETE") { _deleteWindowCommand(req, res); //< close window } else if (req.method === "POST") { _postWindowCommand(req, res); //< change focus to the given window } return; } else if (req.urlParsed.chunks[0] === _const.WINDOW) { _doWindowHandleCommands(req, res); return; } else if (req.urlParsed.file === _const.ELEMENT && req.method === "POST" && req.urlParsed.chunks.length === 1) { //< ".../element" _locator.handleLocateCommand(req, res, _locator.locateElement); return; } else if (req.urlParsed.file === _const.ELEMENTS && req.method === "POST" && req.urlParsed.chunks.length === 1) { //< ".../elements" _locator.handleLocateCommand(req, res, _locator.locateElements); return; } else if (req.urlParsed.chunks[0] === _const.ELEMENT && req.urlParsed.chunks[1] === _const.ACTIVE && req.method === "POST") { //< ".../element/active" _locator.handleLocateCommand(req, res, _locator.locateActiveElement); return; } else if (req.urlParsed.chunks[0] === _const.ELEMENT) { //< ".../element/:elementId/COMMAND" // Get the WebElementRH and, if found, re-route request to it element = new ghostdriver.WebElementReqHand(req.urlParsed.chunks[1], _session); if (element !== null) { _protoParent.reroute.call(element, req, res, _const.ELEMENT_DIR + req.urlParsed.chunks[1]); } else { throw _errors.createInvalidReqVariableResourceNotFoundEH(req); } return; } else if (req.urlParsed.file === _const.TITLE && req.method === "GET") { //< ".../title" // Get the current Page title _getTitleCommand(req, res); return; } else if (req.urlParsed.file === _const.KEYS && req.method === "POST") { _postKeysCommand(req, res); return; } else if (req.urlParsed.file === _const.FORWARD && req.method === "POST") { _forwardCommand(req, res); return; } else if (req.urlParsed.file === _const.BACK && req.method === "POST") { _backCommand(req, res); return; } else if (req.urlParsed.file === _const.REFRESH && req.method === "POST") { _refreshCommand(req, res); return; } else if (req.urlParsed.file === _const.EXECUTE && req.urlParsed.directory === "/" && req.method == "POST") { _executeCommand(req, res); return; } else if (req.urlParsed.file === _const.EXECUTE_ASYNC && req.method === "POST") { _executeAsyncCommand(req, res); return; } else if ((req.urlParsed.file === _const.TIMEOUTS || req.urlParsed.directory === _const.TIMEOUTS_DIR) && req.method === "POST") { _postTimeout(req, res); return; } else if (req.urlParsed.file === _const.WINDOW_HANDLE && req.method === "GET") { _getWindowHandle(req, res); return; } else if (req.urlParsed.file === _const.WINDOW_HANDLES && req.method === "GET") { _getWindowHandles(req, res); return; } else if (req.urlParsed.file === _const.FRAME && req.method === "POST") { _postFrameCommand(req, res); return; } else if (req.urlParsed.file === _const.SOURCE && req.method === "GET") { _getSourceCommand(req, res); return; } else if (req.urlParsed.file === _const.MOVE_TO && req.method === "POST") { _postMouseMoveToCommand(req, res); return; } else if (req.urlParsed.file === _const.PHANTOM_EXEC && req.urlParsed.directory === _const.PHANTOM_DIR && req.method === "POST") { _executePhantomJS(req, res); return; } else if (req.urlParsed.file === _const.CLICK && req.method === "POST") { _postMouseClickCommand(req, res, "click"); return; } else if (req.urlParsed.file === _const.BUTTON_DOWN && req.method === "POST") { _postMouseClickCommand(req, res, "mousedown"); return; } else if (req.urlParsed.file === _const.BUTTON_UP && req.method === "POST") { _postMouseClickCommand(req, res, "mouseup"); return; } else if (req.urlParsed.file === _const.DOUBLE_CLICK && req.method === "POST") { _postMouseClickCommand(req, res, "doubleclick"); return; } else if (req.urlParsed.chunks[0] === _const.COOKIE) { if (req.method === "POST") { _postCookieCommand(req, res); } else if (req.method === "GET") { _getCookieCommand(req, res); } else if(req.method === "DELETE") { _deleteCookieCommand(req, res); } return; } else if (req.urlParsed.chunks[0] === _const.LOG && req.method === "POST") { //< ".../log" _postLog(req, res); return; } else if (req.urlParsed.chunks[0] === _const.LOG && req.urlParsed.chunks[1] === _const.TYPES && req.method === "GET") { //< ".../log/types" _getLogTypes(req, res); return; } else if (req.urlParsed.chunks[0] === _const.LOG && _session.getLogTypes().indexOf(req.urlParsed.chunks[1]) >= 0 && req.method === "GET") { //< ".../log/LOG_TYPE" _getLog(req, res, req.urlParsed.chunks[1]); return; } throw _errors.createInvalidReqInvalidCommandMethodEH(req); }, _createOnSuccessHandler = function(res) { return function (status) { _log.debug("_SuccessHandler", "status: " + status); res.success(_session.getId()); }; }, _doWindowHandleCommands = function(req, res) { var windowHandle, command, targetWindow; _log.debug("_doWindowHandleCommands", JSON.stringify(req)); // Ensure all the parameters are provided if (req.urlParsed.chunks.length === 3) { windowHandle = req.urlParsed.chunks[1]; command = req.urlParsed.chunks[2]; // Fetch the right window if (windowHandle === _const.CURRENT) { targetWindow = _protoParent.getSessionCurrWindow.call(this, _session, req); } else { targetWindow = _protoParent.getSessionWindow.call(this, windowHandle, _session, req); } // Act on the window (page) if(command === _const.SIZE && req.method === "POST") { _postWindowSizeCommand(req, res, targetWindow); return; } else if(command === _const.SIZE && req.method === "GET") { _getWindowSizeCommand(req, res, targetWindow); return; } else if(command === _const.POSITION && req.method === "POST") { _postWindowPositionCommand(req, res, targetWindow); return; } else if(command === _const.POSITION && req.method === "GET") { _getWindowPositionCommand(req, res, targetWindow); return; } else if(command === _const.MAXIMIZE && req.method === "POST") { _postWindowMaximizeCommand(req, res, targetWindow); return; } // No command matched: error throw _errors.createInvalidReqInvalidCommandMethodEH(req); } else { throw _errors.createInvalidReqMissingCommandParameterEH(req); } }, _postWindowSizeCommand = function(req, res, targetWindow) { var params = JSON.parse(req.post), newWidth = params.width, newHeight = params.height; // If width/height are passed in string, force them to numbers if (typeof(params.width) === "string") { newWidth = parseInt(params.width, 10); } if (typeof(params.height) === "string") { newHeight = parseInt(params.height, 10); } // If a number was not found, the command is if (isNaN(newWidth) || isNaN(newHeight)) { throw _errors.createInvalidReqInvalidCommandMethodEH(req); } targetWindow.viewportSize = { width : newWidth, height : newHeight }; res.success(_session.getId()); }, _getWindowSizeCommand = function(req, res, targetWindow) { // Returns response in the format "{width: number, height: number}" res.success(_session.getId(), targetWindow.viewportSize); }, _postWindowPositionCommand = function(req, res, targetWindow) { var params = JSON.parse(req.post), newX = params.x, newY = params.y; // If width/height are passed in string, force them to numbers if (typeof(params.x) === "string") { newX = parseInt(params.x, 10); } if (typeof(params.y) === "string") { newY = parseInt(params.y, 10); } // If a number was not found, the command is if (isNaN(newX) || isNaN(newY)) { throw _errors.createInvalidReqInvalidCommandMethodEH(req); } // NOTE: Nothing to do! PhantomJS is headless. :) res.success(_session.getId()); }, _getWindowPositionCommand = function(req, res, targetWindow) { // Returns response in the format "{width: number, height: number}" res.success(_session.getId(), { x : 0, y : 0 }); }, _postWindowMaximizeCommand = function(req, res, targetWindow) { // NOTE: PhantomJS is headless, so there is no "screen" to maximize to // or "window" resize to that. // // NOTE: The most common screen resolution used online is currently: 1366x768 // See http://gs.statcounter.com/#resolution-ww-monthly-201307-201312. targetWindow.viewportSize = { width : 1366, height : 768 }; res.success(_session.getId()); }, _postKeysCommand = function(req, res) { var activeEl = _locator.locateActiveElement(); var elReqHand = new ghostdriver.WebElementReqHand(activeEl.value, _session); elReqHand.postValueCommand(req, res); }, _refreshCommand = function(req, res) { var successHand = _createOnSuccessHandler(res), currWindow = _protoParent.getSessionCurrWindow.call(this, _session, req); currWindow.execFuncAndWaitForLoad( function() { currWindow.reload(); }, successHand, successHand); //< We don't care if 'refresh' fails }, _backCommand = function(req, res) { var successHand = _createOnSuccessHandler(res), currWindow = _protoParent.getSessionCurrWindow.call(this, _session, req); if (currWindow.canGoBack) { currWindow.execFuncAndWaitForLoad( function() { currWindow.goBack(); }, successHand, successHand); //< We don't care if 'back' fails } else { // We can't go back, and that's ok successHand(); } }, _forwardCommand = function(req, res) { var successHand = _createOnSuccessHandler(res), currWindow = _protoParent.getSessionCurrWindow.call(this, _session, req); if (currWindow.canGoForward) { currWindow.execFuncAndWaitForLoad( function() { currWindow.goForward(); }, successHand, successHand); //< We don't care if 'forward' fails } else { // We can't go forward, and that's ok successHand(); } }, _executeCommand = function(req, res) { var postObj = JSON.parse(req.post), result, timer, scriptTimeout = _session.getScriptTimeout(), timedOut = false; if (typeof(postObj) === "object" && postObj.script && postObj.args) { // Execute script, but within a limited timeframe timer = setTimeout(function() { // The script didn't return within the expected timeframe timedOut = true; _errors.handleFailedCommandEH( _errors.FAILED_CMD_STATUS.TIMEOUT, "Script didn't return within " + scriptTimeout + "ms", req, res, _session, "SessionReqHand"); }, scriptTimeout); // Launch the actual script result = _protoParent.getSessionCurrWindow.call(this, _session, req).evaluate( require("./webdriver_atoms.js").get("execute_script"), postObj.script, postObj.args, true); // If we are here, we don't need the timer anymore clearTimeout(timer); // Respond with result ONLY if this hasn't ALREADY timed-out if (!timedOut) { res.respondBasedOnResult(_session, req, result); } } else { throw _errors.createInvalidReqMissingCommandParameterEH(req); } }, _executeAsyncCommand = function(req, res) { var postObj = JSON.parse(req.post); _log.debug("_executeAsyncCommand", JSON.stringify(postObj)); if (typeof(postObj) === "object" && postObj.script && postObj.args) { _protoParent.getSessionCurrWindow.call(this, _session, req).setOneShotCallback("onCallback", function() { _log.debug("_executeAsyncCommand.callbackArguments", JSON.stringify(arguments)); res.respondBasedOnResult(_session, req, arguments[0]); }); _protoParent.getSessionCurrWindow.call(this, _session, req).evaluate( "function(script, args, timeout) { " + "return (" + require("./webdriver_atoms.js").get("execute_async_script") + ")" + "(script, args, timeout, callPhantom, true); " + "}", postObj.script, postObj.args, _session.getScriptTimeout()); } else { throw _errors.createInvalidReqMissingCommandParameterEH(req); } }, _getWindowHandle = function (req, res) { var handle; // Get current window handle handle = _session.getCurrentWindowHandle(); if (handle !== null) { res.success(_session.getId(), handle); } else { throw _errors.createFailedCommandEH( _errors.FAILED_CMD_STATUS.NO_SUCH_WINDOW, //< error name "Current window handle invalid (closed?)", //< error message req, //< request _session, //< session "SessionReqHand"); //< class name } }, _getWindowHandles = function(req, res) { res.success(_session.getId(), _session.getWindowHandles()); }, _getScreenshotCommand = function(req, res) { var rendering = _protoParent.getSessionCurrWindow.call(this, _session, req).renderBase64("png"); res.success(_session.getId(), rendering); }, _getUrlCommand = function(req, res) { // Get the URL at which the Page currently is var result = _protoParent.getSessionCurrWindow.call(this, _session, req).evaluate( require("./webdriver_atoms.js").get("execute_script"), "return location.toString()", []); res.respondBasedOnResult(_session, res, result); }, _postUrlCommand = function(req, res) { // Load the given URL in the Page var postObj = JSON.parse(req.post), currWindow = _protoParent.getSessionCurrWindow.call(this, _session, req); _log.debug("_postUrlCommand", "Session '"+ _session.getId() +"' is about to load URL: " + postObj.url); if (typeof(postObj) === "object" && postObj.url) { // Switch to the main frame first currWindow.switchToMainFrame(); // Load URL and wait for load to finish (or timeout) currWindow.execFuncAndWaitForLoad(function() { currWindow.open(postObj.url.trim()); }, _createOnSuccessHandler(res), //< success function(errMsg) { //< failure/timeout var errCode = errMsg === "timeout" ? _errors.FAILED_CMD_STATUS.TIMEOUT : _errors.FAILED_CMD_STATUS.UNKNOWN_ERROR; // Report error _errors.handleFailedCommandEH( errCode, "URL '" + postObj.url + "' didn't load. Error: '" + errMsg + "'", req, res, _session, "SessionReqHand"); }); } else { throw _errors.createInvalidReqMissingCommandParameterEH(req); } }, _postTimeout = function(req, res) { var postObj = JSON.parse(req.post); // Normalize the call: the "type" is read from the URL, not a POST parameter if (req.urlParsed.file === _const.IMPLICIT_WAIT) { postObj["type"] = _session.timeoutNames.IMPLICIT; } else if (req.urlParsed.file === _const.ASYNC_SCRIPT) { postObj["type"] = _session.timeoutNames.SCRIPT; } if (typeof(postObj["type"]) === "string" && typeof(postObj["ms"]) === "number") { _log.debug("_postTimeout", JSON.stringify(postObj)); // Set the right timeout on the Session switch(postObj["type"]) { case _session.timeoutNames.SCRIPT: _session.setScriptTimeout(postObj["ms"]); break; case _session.timeoutNames.IMPLICIT: _session.setImplicitTimeout(postObj["ms"]); break; case _session.timeoutNames.PAGE_LOAD: _session.setPageLoadTimeout(postObj["ms"]); break; default: throw _errors.createInvalidReqMissingCommandParameterEH(req); } res.success(_session.getId()); } else { throw _errors.createInvalidReqMissingCommandParameterEH(req); } }, _postFrameCommand = function(req, res) { var postObj = JSON.parse(req.post), frameName, framePos, switched = false, currWindow = _protoParent.getSessionCurrWindow.call(this, _session, req); _log.debug("_postFrameCommand", "Current frames count: " + currWindow.framesCount); if (typeof(postObj) === "object" && typeof(postObj.id) !== "undefined") { if(postObj.id === null) { _log.debug("_postFrameCommand", "Switching to 'null' (main frame)"); // Reset focus on the topmost (main) Frame currWindow.switchToMainFrame(); switched = true; } else if (typeof(postObj.id) === "number") { _log.debug("_postFrameCommand", "Switching to frame number: " + postObj.id); // Switch frame by "index" switched = currWindow.switchToFrame(postObj.id); } else if (typeof(postObj.id) === "string") { // Switch frame by "name" or by "id" _log.debug("_postFrameCommand", "Switching to frame #id: " + postObj.id); switched = currWindow.switchToFrame(postObj.id); // If we haven't switched, let's try to find the frame "name" using it's "id" if (!switched) { // fetch the frame "name" via "id" frameName = currWindow.evaluate(function(frameId) { var el = null; el = document.querySelector('#'+frameId); if (el !== null) { return el.name; } return null; }, postObj.id); _log.debug("_postFrameCommand", "Failed to switch by #id, trying by name: " + frameName); // Switch frame by "name" if (frameName !== null) { switched = currWindow.switchToFrame(frameName); } if (!switched) { // fetch the frame "position" via "id" framePos = currWindow.evaluate(function(frameIdOrName) { var allFrames = document.querySelectorAll("frame,iframe"), theFrame = document.querySelector('#'+frameIdOrName) || document.querySelector('[name='+frameIdOrName+']'), i; for (i = allFrames.length -1; i >= 0; --i) { if (allFrames[i].contentWindow === theFrame.contentWindow) { return i; } } }, postObj.id); if (framePos >= 0) { _log.debug("_postFrameCommand", "Failed to switch by #id or name, trying by position: "+framePos); switched = currWindow.switchToFrame(framePos); } else { _log.warn("_postFrameCommand", "Unable to locate the Frame!"); } } } } else if (typeof(postObj.id) === "object" && typeof(postObj.id["ELEMENT"]) === "string") { _log.debug("_postFrameCommand.element", JSON.stringify(postObj.id)); // Will use the Element JSON to find the frame name frameName = currWindow.evaluate( require("./webdriver_atoms.js").get("execute_script"), "if (!arguments[0].name && !arguments[0].id) { " + " arguments[0].name = '_random_name_id_' + new Date().getTime(); " + " arguments[0].id = arguments[0].name; " + "} " + "return arguments[0].name || arguments[0].id;", [postObj.id]); _log.debug("_postFrameCommand.frameName", frameName.value); // If a frame name (or id) is found for the given ELEMENT, we // "re-call" this very function, changing the `post` property // on the `req` object. The `post` will contain this time // the frame name (or id) that was found. if (frameName && frameName.value) { req.post = "{\"id\" : \"" + frameName.value + "\"}"; _postFrameCommand.call(this, req, res); return; } } else { throw _errors.createInvalidReqInvalidCommandMethodEH(req); } // Send a positive response if the switch was successful if (switched) { res.success(_session.getId()); } else { // ... otherwise, throw the appropriate exception throw _errors.createFailedCommandEH( _errors.FAILED_CMD_STATUS.NO_SUCH_FRAME, //< error name "Unable to switch to frame", //< error message req, //< request _session, //< session "SessionReqHand"); //< class name } } else { throw _errors.createInvalidReqMissingCommandParameterEH(req); } }, _getSourceCommand = function(req, res) { var source = _protoParent.getSessionCurrWindow.call(this, _session, req).frameContent; res.success(_session.getId(), source); }, _postMouseMoveToCommand = function(req, res) { var postObj = JSON.parse(req.post), coords = { x: 0, y: 0 }, elementLocation, elementSize, elementSpecified = false, offsetSpecified = false; if (typeof postObj === "object") { elementSpecified = postObj.element && postObj.element != null; offsetSpecified = typeof postObj.xoffset !== "undefined" && typeof postObj.yoffset !== "undefined"; } // Check that either an Element ID or an X-Y Offset was provided if (elementSpecified || offsetSpecified) { _log.debug("_postMouseMoveToCommand", "element: " + elementSpecified + ", offset: " + offsetSpecified); // If an Element was provided... if (elementSpecified) { // Get Element's Location and add it to the coordinates var requestHandler = new ghostdriver.WebElementReqHand(postObj.element, _session); elementLocation = requestHandler.getLocationInView(); elementSize = requestHandler.getSize(); // If the Element has a valid location if (elementLocation !== null) { coords.x = elementLocation.x; coords.y = elementLocation.y; } } else { coords = _session.inputs.getCurrentCoordinates(); } _log.debug("_postMouseMoveToCommand", "initial coordinates: (" + coords.x + "," + coords.y + ")"); if (elementSpecified && !offsetSpecified && elementSize !== null) { coords.x += Math.floor(elementSize.width / 2); coords.y += Math.floor(elementSize.height / 2); } else { // Add up the offset (if any) coords.x += postObj.xoffset || 0; coords.y += postObj.yoffset || 0; } _log.debug("_postMouseMoveToCommand", "coordinates adjusted to: (" + coords.x + "," + coords.y + ")"); // Send the Mouse Move as native event _session.inputs.mouseMove(_session, coords); res.success(_session.getId()); } else { // Neither "element" nor "xoffset/yoffset" were provided throw _errors.createInvalidReqMissingCommandParameterEH(req); } }, _postMouseClickCommand = function(req, res, clickType) { var postObj = {}, mouseButton = "left"; // normalize click clickType = clickType || "click"; // The protocol allows language bindings to send an empty string (or no data at all) if (req.post && req.post.length > 0) { postObj = JSON.parse(req.post); } // Check that either an Element ID or an X-Y Offset was provided if (typeof(postObj) === "object") { // Determine which button to click if (typeof(postObj.button) === "number") { // 0 is left, 1 is middle, 2 is right mouseButton = (postObj.button === 2) ? "right" : (postObj.button === 1) ? "middle" : "left"; } // Send the Mouse Click as native event _session.inputs.mouseButtonClick(_session, clickType, mouseButton); res.success(_session.getId()); } else { // Neither "element" nor "xoffset/yoffset" were provided throw _errors.createInvalidReqMissingCommandParameterEH(req); } }, _postCookieCommand = function(req, res) { var postObj = JSON.parse(req.post || "{}"), currWindow = _protoParent.getSessionCurrWindow.call(this, _session, req); // If the page has not loaded anything yet, setting cookies is forbidden if (currWindow.url.indexOf("about:blank") === 0) { // Something else went wrong _errors.handleFailedCommandEH( _errors.FAILED_CMD_STATUS.UNABLE_TO_SET_COOKIE, "Unable to set Cookie: no URL has been loaded yet", req, res, _session, "SessionReqHand"); return; } if (postObj.cookie) { // JavaScript deals with Timestamps in "milliseconds since epoch": normalize! if (postObj.cookie.expiry) { postObj.cookie.expiry *= 1000; } // If the cookie is expired OR if it was successfully added if ((postObj.cookie.expiry && postObj.cookie.expiry <= new Date().getTime()) || currWindow.addCookie(postObj.cookie)) { // Notify success res.success(_session.getId()); } else { // Something went wrong while trying to set the cookie if (currWindow.url.indexOf(postObj.cookie.domain) < 0) { // Domain mismatch _errors.handleFailedCommandEH( _errors.FAILED_CMD_STATUS.INVALID_COOKIE_DOMAIN, "Can only set Cookies for the current domain", req, res, _session, "SessionReqHand"); } else { // Something else went wrong _errors.handleFailedCommandEH( _errors.FAILED_CMD_STATUS.UNABLE_TO_SET_COOKIE, "Unable to set Cookie", req, res, _session, "SessionReqHand"); } } } else { throw _errors.createInvalidReqMissingCommandParameterEH(req); } }, _getCookieCommand = function(req, res) { // Get all the cookies the session at current URL can see/access res.success( _session.getId(), _protoParent.getSessionCurrWindow.call(this, _session, req).cookies); }, _deleteCookieCommand = function(req, res) { if (req.urlParsed.chunks.length === 2) { // delete only 1 cookie among the one visible to this page _protoParent.getSessionCurrWindow.call(this, _session, req).deleteCookie(req.urlParsed.chunks[1]); } else { // delete all the cookies visible to this page _protoParent.getSessionCurrWindow.call(this, _session, req).clearCookies(); } res.success(_session.getId()); }, _deleteWindowCommand = function(req, res) { var params = JSON.parse(req.post || "{}"), //< in case nothing is posted at all closed = false; // Use the "name" parameter if it was provided if (typeof(params) === "object" && params.name) { closed = _session.closeWindow(params.name); } else { closed = _session.closeCurrentWindow(); } // Report a success if we manage to close the window, // otherwise throw a Failed Command Error if (closed) { res.success(_session.getId()); } else { throw _errors.createFailedCommandEH( _errors.FAILED_CMD_STATUS.NO_SUCH_WINDOW, //< error name "Unable to close window (closed already?)", //< error message req, //< request _session, //< session "SessionReqHand"); //< class name } }, _postWindowCommand = function(req, res) { var params = JSON.parse(req.post); if (typeof(params) === "object" && typeof(params.name) === "string") { // Report a success if we manage to switch the current window, // otherwise throw a Failed Command Error if (_session.switchToWindow(params.name)) { res.success(_session.getId()); } else { throw _errors.createFailedCommandEH( _errors.FAILED_CMD_STATUS.NO_SUCH_WINDOW, //< error name "Unable to switch to window (closed?)", //< error message req, //< request _session, //< session "SessionReqHand"); //< class name } } else { throw _errors.createInvalidReqMissingCommandParameterEH(req); } }, _getTitleCommand = function(req, res) { res.success(_session.getId(), _protoParent.getSessionCurrWindow.call(this, _session, req).title); }, _executePhantomJS = function(req, res) { var params = JSON.parse(req.post); if (typeof(params) === "object" && params.script && params.args) { res.success(_session.getId(), _session.executePhantomJS(_protoParent.getSessionCurrWindow.call(this, _session, req), params.script, params.args)); } else { throw _errors.createInvalidReqMissingCommandParameterEH(req); } }, _postLog = function (req, res) { var params = JSON.parse(req.post); if (!params.type || _session.getLogTypes().indexOf(params.type) < 0) { throw _errors.createInvalidReqMissingCommandParameterEH(req); } _getLog(req, res, params.type); }, _getLogTypes = function (req, res) { res.success(_session.getId(), _session.getLogTypes()); }, _getLog = function (req, res, logType) { res.success(_session.getId(), _session.getLog(logType)); }; // public: return { handle : _handle, getSessionId : function() { return _session.getId(); } }; }; // prototype inheritance: ghostdriver.SessionReqHand.prototype = new ghostdriver.RequestHandler();