diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 00000000000..2f9ddb9b8a3 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,20 @@ +Copyright (c) 2011 Camilo Tapia + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/webdriverjs/all.commands.txt b/all.commands.txt similarity index 100% rename from node_modules/webdriverjs/all.commands.txt rename to all.commands.txt diff --git a/selenium.server/selenium-server-standalone-2.31.0.jar b/bin/selenium-server-standalone-2.31.0.jar similarity index 100% rename from selenium.server/selenium-server-standalone-2.31.0.jar rename to bin/selenium-server-standalone-2.31.0.jar diff --git a/node_modules/webdriverjs/lib/asserts/textContains.js b/lib/asserts/textContains.js similarity index 100% rename from node_modules/webdriverjs/lib/asserts/textContains.js rename to lib/asserts/textContains.js diff --git a/lib/assets/colors.js b/lib/assets/colors.js new file mode 100644 index 00000000000..3c18b72b1b9 --- /dev/null +++ b/lib/assets/colors.js @@ -0,0 +1,35 @@ +/** + * webdriverjs + * https://github.com/Camme/webdriverjs + * + * useful colors for bash + * + * Copyright (c) 2013 Camilo Tapia + * Licensed under the MIT license. + * + * Contributors: + * Dan Jenkins + * Christian Bromann + */ + +'use strict'; + +module.exports = { + black: "\x1b[0;30m", + dkgray: "\x1b[1;30m", + brick: "\x1b[0;31m", + red: "\x1b[1;31m", + green: "\x1b[0;32m", + lime: "\x1b[1;32m", + brown: "\x1b[0;33m", + yellow: "\x1b[1;33m", + navy: "\x1b[0;34m", + blue: "\x1b[1;34m", + violet: "\x1b[0;35m", + magenta: "\x1b[1;35m", + teal: "\x1b[0;36m", + cyan: "\x1b[1;36m", + ltgray: "\x1b[0;37m", + white: "\x1b[1;37m", + reset: "\x1b[0m" +}; \ No newline at end of file diff --git a/lib/assets/errorCodes.js b/lib/assets/errorCodes.js new file mode 100644 index 00000000000..c0cdbfa4148 --- /dev/null +++ b/lib/assets/errorCodes.js @@ -0,0 +1,41 @@ +/** + * webdriverjs + * https://github.com/Camme/webdriverjs + * + * error codes + * + * Copyright (c) 2013 Camilo Tapia + * Licensed under the MIT license. + * + * Contributors: + * Dan Jenkins + * Christian Bromann + */ + +'use strict'; + +module.exports = { + "-1": {id: "Unknown", message: "Remote end send an unknown status code."}, + "0": {id: "Success", message: "The command executed successfully."}, + "7": {id: "NoSuchElement", message: "An element could not be located on the page using the given search parameters."}, + "8": {id: "NoSuchFrame", message: "A request to switch to a frame could not be satisfied because the frame could not be found."}, + "9": {id: "UnknownCommand", message: "The requested resource could not be found, or a request was received using an HTTP method that is not supported by the mapped resource."}, + "10": {id: "StaleElementReference", message: "An element command failed because the referenced element is no longer attached to the DOM."}, + "11": {id: "ElementNotVisible", message: "An element command could not be completed because the element is not visible on the page."}, + "12": {id: "InvalidElementState", message: "An element command could not be completed because the element is in an invalid state (e.g. attempting to click a disabled element)."}, + "13": {id: "UnknownError", message: "An unknown server-side error occurred while processing the command."}, + "15": {id: "ElementIsNotSelectable", message: "An attempt was made to select an element that cannot be selected."}, + "17": {id: "JavaScriptError", message: "An error occurred while executing user supplied JavaScript."}, + "19": {id: "XPathLookupError", message: "An error occurred while searching for an element by XPath."}, + "23": {id: "NoSuchWindow", message: "A request to switch to a different window could not be satisfied because the window could not be found."}, + "24": {id: "InvalidCookieDomain", message: "An illegal attempt was made to set a cookie under a different domain than the current page."}, + "25": {id: "UnableToSetCookie", message: "A request to set a cookie's value could not be satisfied."}, + "26": {id: "UnexpectedAlertOpen", message: "A modal dialog was open, blocking this operation"}, + "27": {id: "NoAlertOpenError", message: "An attempt was made to operate on a modal dialog when one was not open."}, + "28": {id: "ScriptTimeout", message: "A script did not complete before its timeout expired."}, + "29": {id: "InvalidElementCoordinates", message: "The coordinates provided to an interactions operation are invalid."}, + "30": {id: "IMENotAvailable", message: "IME was not available."}, + "31": {id : "IMEEngineActivationFailed", message: "An IME engine could not be started."}, + "32": {id: "InvalidSelector", message: "Argument was an invalid selector (e.g. XPath/CSS)."}, + "34": {id: "ElementNotScrollable", message: "Element cannot be scrolled into view."} +}; \ No newline at end of file diff --git a/node_modules/webdriverjs/lib/commands/buttonClick.js b/lib/commands/buttonClick.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/buttonClick.js rename to lib/commands/buttonClick.js diff --git a/node_modules/webdriverjs/lib/commands/clearElement.js b/lib/commands/clearElement.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/clearElement.js rename to lib/commands/clearElement.js diff --git a/node_modules/webdriverjs/lib/commands/click.js b/lib/commands/click.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/click.js rename to lib/commands/click.js diff --git a/node_modules/webdriverjs/lib/commands/doubleClick.js b/lib/commands/doubleClick.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/doubleClick.js rename to lib/commands/doubleClick.js diff --git a/node_modules/webdriverjs/lib/commands/dragAndDrop.js b/lib/commands/dragAndDrop.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/dragAndDrop.js rename to lib/commands/dragAndDrop.js diff --git a/node_modules/webdriverjs/lib/commands/end.js b/lib/commands/end.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/end.js rename to lib/commands/end.js diff --git a/node_modules/webdriverjs/lib/commands/facebookLogin.js b/lib/commands/facebookLogin.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/facebookLogin.js rename to lib/commands/facebookLogin.js diff --git a/node_modules/webdriverjs/lib/commands/getAttribute.js b/lib/commands/getAttribute.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/getAttribute.js rename to lib/commands/getAttribute.js diff --git a/node_modules/webdriverjs/lib/commands/getCssProperty.js b/lib/commands/getCssProperty.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/getCssProperty.js rename to lib/commands/getCssProperty.js diff --git a/node_modules/webdriverjs/lib/commands/getElementCssProperty.js b/lib/commands/getElementCssProperty.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/getElementCssProperty.js rename to lib/commands/getElementCssProperty.js diff --git a/node_modules/webdriverjs/lib/commands/getElementSize.js b/lib/commands/getElementSize.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/getElementSize.js rename to lib/commands/getElementSize.js diff --git a/node_modules/webdriverjs/lib/commands/getLocation.js b/lib/commands/getLocation.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/getLocation.js rename to lib/commands/getLocation.js diff --git a/node_modules/webdriverjs/lib/commands/getLocationInView.js b/lib/commands/getLocationInView.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/getLocationInView.js rename to lib/commands/getLocationInView.js diff --git a/node_modules/webdriverjs/lib/commands/getSize.js b/lib/commands/getSize.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/getSize.js rename to lib/commands/getSize.js diff --git a/node_modules/webdriverjs/lib/commands/getSource.js b/lib/commands/getSource.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/getSource.js rename to lib/commands/getSource.js diff --git a/node_modules/webdriverjs/lib/commands/getTagName.js b/lib/commands/getTagName.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/getTagName.js rename to lib/commands/getTagName.js diff --git a/node_modules/webdriverjs/lib/commands/getText.js b/lib/commands/getText.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/getText.js rename to lib/commands/getText.js diff --git a/node_modules/webdriverjs/lib/commands/getTitle.js b/lib/commands/getTitle.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/getTitle.js rename to lib/commands/getTitle.js diff --git a/node_modules/webdriverjs/lib/commands/getValue.js b/lib/commands/getValue.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/getValue.js rename to lib/commands/getValue.js diff --git a/node_modules/webdriverjs/lib/commands/isSelected.js b/lib/commands/isSelected.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/isSelected.js rename to lib/commands/isSelected.js diff --git a/node_modules/webdriverjs/lib/commands/isVisible.js b/lib/commands/isVisible.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/isVisible.js rename to lib/commands/isVisible.js diff --git a/node_modules/webdriverjs/lib/commands/lazySetValue.js b/lib/commands/lazySetValue.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/lazySetValue.js rename to lib/commands/lazySetValue.js diff --git a/node_modules/webdriverjs/lib/commands/moveToObject.js b/lib/commands/moveToObject.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/moveToObject.js rename to lib/commands/moveToObject.js diff --git a/node_modules/webdriverjs/lib/commands/pause.js b/lib/commands/pause.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/pause.js rename to lib/commands/pause.js diff --git a/node_modules/webdriverjs/lib/commands/saveScreenshot.js b/lib/commands/saveScreenshot.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/saveScreenshot.js rename to lib/commands/saveScreenshot.js diff --git a/node_modules/webdriverjs/lib/commands/sendKeys.js b/lib/commands/sendKeys.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/sendKeys.js rename to lib/commands/sendKeys.js diff --git a/node_modules/webdriverjs/lib/commands/setValue.js b/lib/commands/setValue.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/setValue.js rename to lib/commands/setValue.js diff --git a/node_modules/webdriverjs/lib/commands/submitForm.js b/lib/commands/submitForm.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/submitForm.js rename to lib/commands/submitForm.js diff --git a/node_modules/webdriverjs/lib/commands/waitFor.js b/lib/commands/waitFor.js similarity index 100% rename from node_modules/webdriverjs/lib/commands/waitFor.js rename to lib/commands/waitFor.js diff --git a/node_modules/webdriverjs/lib/protocol/back.js b/lib/protocol/back.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/back.js rename to lib/protocol/back.js diff --git a/node_modules/webdriverjs/lib/protocol/buttonDown.js b/lib/protocol/buttonDown.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/buttonDown.js rename to lib/protocol/buttonDown.js diff --git a/node_modules/webdriverjs/lib/protocol/buttonUp.js b/lib/protocol/buttonUp.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/buttonUp.js rename to lib/protocol/buttonUp.js diff --git a/node_modules/webdriverjs/lib/protocol/doDoubleClick.js b/lib/protocol/doDoubleClick.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/doDoubleClick.js rename to lib/protocol/doDoubleClick.js diff --git a/node_modules/webdriverjs/lib/protocol/element.js b/lib/protocol/element.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/element.js rename to lib/protocol/element.js diff --git a/node_modules/webdriverjs/lib/protocol/elementIdAttribute.js b/lib/protocol/elementIdAttribute.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elementIdAttribute.js rename to lib/protocol/elementIdAttribute.js diff --git a/node_modules/webdriverjs/lib/protocol/elementIdClear.js b/lib/protocol/elementIdClear.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elementIdClear.js rename to lib/protocol/elementIdClear.js diff --git a/node_modules/webdriverjs/lib/protocol/elementIdClick.js b/lib/protocol/elementIdClick.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elementIdClick.js rename to lib/protocol/elementIdClick.js diff --git a/node_modules/webdriverjs/lib/protocol/elementIdCssProperty.js b/lib/protocol/elementIdCssProperty.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elementIdCssProperty.js rename to lib/protocol/elementIdCssProperty.js diff --git a/node_modules/webdriverjs/lib/protocol/elementIdDisplayed.js b/lib/protocol/elementIdDisplayed.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elementIdDisplayed.js rename to lib/protocol/elementIdDisplayed.js diff --git a/node_modules/webdriverjs/lib/protocol/elementIdElement.js b/lib/protocol/elementIdElement.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elementIdElement.js rename to lib/protocol/elementIdElement.js diff --git a/node_modules/webdriverjs/lib/protocol/elementIdKeys.js b/lib/protocol/elementIdKeys.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elementIdKeys.js rename to lib/protocol/elementIdKeys.js diff --git a/node_modules/webdriverjs/lib/protocol/elementIdLocation.js b/lib/protocol/elementIdLocation.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elementIdLocation.js rename to lib/protocol/elementIdLocation.js diff --git a/node_modules/webdriverjs/lib/protocol/elementIdLocationInView.js b/lib/protocol/elementIdLocationInView.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elementIdLocationInView.js rename to lib/protocol/elementIdLocationInView.js diff --git a/node_modules/webdriverjs/lib/protocol/elementIdName.js b/lib/protocol/elementIdName.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elementIdName.js rename to lib/protocol/elementIdName.js diff --git a/node_modules/webdriverjs/lib/protocol/elementIdSelected.js b/lib/protocol/elementIdSelected.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elementIdSelected.js rename to lib/protocol/elementIdSelected.js diff --git a/node_modules/webdriverjs/lib/protocol/elementIdSize.js b/lib/protocol/elementIdSize.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elementIdSize.js rename to lib/protocol/elementIdSize.js diff --git a/node_modules/webdriverjs/lib/protocol/elementIdText.js b/lib/protocol/elementIdText.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elementIdText.js rename to lib/protocol/elementIdText.js diff --git a/node_modules/webdriverjs/lib/protocol/elementIdValue.js b/lib/protocol/elementIdValue.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elementIdValue.js rename to lib/protocol/elementIdValue.js diff --git a/node_modules/webdriverjs/lib/protocol/elements.js b/lib/protocol/elements.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/elements.js rename to lib/protocol/elements.js diff --git a/node_modules/webdriverjs/lib/protocol/execute.js b/lib/protocol/execute.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/execute.js rename to lib/protocol/execute.js diff --git a/node_modules/webdriverjs/lib/protocol/forward.js b/lib/protocol/forward.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/forward.js rename to lib/protocol/forward.js diff --git a/node_modules/webdriverjs/lib/protocol/frame.js b/lib/protocol/frame.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/frame.js rename to lib/protocol/frame.js diff --git a/node_modules/webdriverjs/lib/protocol/init.js b/lib/protocol/init.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/init.js rename to lib/protocol/init.js diff --git a/node_modules/webdriverjs/lib/protocol/moveTo.js b/lib/protocol/moveTo.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/moveTo.js rename to lib/protocol/moveTo.js diff --git a/node_modules/webdriverjs/lib/protocol/refresh.js b/lib/protocol/refresh.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/refresh.js rename to lib/protocol/refresh.js diff --git a/node_modules/webdriverjs/lib/protocol/screenshot.js b/lib/protocol/screenshot.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/screenshot.js rename to lib/protocol/screenshot.js diff --git a/node_modules/webdriverjs/lib/protocol/session.js b/lib/protocol/session.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/session.js rename to lib/protocol/session.js diff --git a/node_modules/webdriverjs/lib/protocol/source.js b/lib/protocol/source.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/source.js rename to lib/protocol/source.js diff --git a/node_modules/webdriverjs/lib/protocol/status.js b/lib/protocol/status.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/status.js rename to lib/protocol/status.js diff --git a/node_modules/webdriverjs/lib/protocol/submit.js b/lib/protocol/submit.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/submit.js rename to lib/protocol/submit.js diff --git a/node_modules/webdriverjs/lib/protocol/title.js b/lib/protocol/title.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/title.js rename to lib/protocol/title.js diff --git a/node_modules/webdriverjs/lib/protocol/url.js b/lib/protocol/url.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/url.js rename to lib/protocol/url.js diff --git a/node_modules/webdriverjs/lib/protocol/value.js b/lib/protocol/value.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/value.js rename to lib/protocol/value.js diff --git a/node_modules/webdriverjs/lib/protocol/window.js b/lib/protocol/window.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/window.js rename to lib/protocol/window.js diff --git a/node_modules/webdriverjs/lib/protocol/windowHandleSize.js b/lib/protocol/windowHandleSize.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/windowHandleSize.js rename to lib/protocol/windowHandleSize.js diff --git a/node_modules/webdriverjs/lib/protocol/windowHandles.js b/lib/protocol/windowHandles.js similarity index 100% rename from node_modules/webdriverjs/lib/protocol/windowHandles.js rename to lib/protocol/windowHandles.js diff --git a/node_modules/webdriverjs/lib/tests/cssPropertyEquals.js b/lib/tests/cssPropertyEquals.js similarity index 100% rename from node_modules/webdriverjs/lib/tests/cssPropertyEquals.js rename to lib/tests/cssPropertyEquals.js diff --git a/node_modules/webdriverjs/lib/tests/titleEquals.js b/lib/tests/titleEquals.js similarity index 100% rename from node_modules/webdriverjs/lib/tests/titleEquals.js rename to lib/tests/titleEquals.js diff --git a/node_modules/webdriverjs/lib/tests/visible.js b/lib/tests/visible.js similarity index 100% rename from node_modules/webdriverjs/lib/tests/visible.js rename to lib/tests/visible.js diff --git a/lib/webdriverjs.js b/lib/webdriverjs.js new file mode 100644 index 00000000000..d51d9e48c87 --- /dev/null +++ b/lib/webdriverjs.js @@ -0,0 +1,768 @@ +/** + * webdriverjs + * https://github.com/Camme/webdriverjs + * + * A WebDriver module for nodejs. Either use the super easy help commands or use the base + * Webdriver wire protocol commands. Its totally inspired by jellyfishs webdriver, but the + * goal is to make all the webdriver protocol items available, as near the original as possible. + * + * Copyright (c) 2013 Camilo Tapia + * Licensed under the MIT license. + * + * Contributors: + * Dan Jenkins + * Christian Bromann + */ + +'use strict'; + +var http = require("http"), + fs = require('fs'), + path = require('path'), + colors = require('assets/colors'), + errorCodes = require('assets/errorCodes'), + infoHasBeenShown = false; + +var WebdriverJs = function(options)//host, port, username, pass) +{ + + options = options || {}; + + var self = this, + startPath = '/wd/hub', + queue = [], + queueIsRunning = false; + + self.chain = true; + self.sessionId = null; + self.queuedPaused = false; + + /* log level + * silent : no logs + * command : command only + * verbose : command + data + */ + self.logLevel = options.logLevel || 'verbose'; + + // where to save the screenshots. default to current folder + self.screenshotPath = ""; + + var defaultOptions = { + host: options.host || 'localhost', + port: options.port || 4444, + method: 'POST' + }; + + // defaultOptions = self.extend(defaultOptions, options); + self.desiredCapabilities = { + browserName: "firefox", + version: "", + javascriptEnabled: true, + platform: "ANY" + }; + + if (options.desiredCapabilities) { + self.desiredCapabilities = self.extend(self.desiredCapabilities, options.desiredCapabilities); + } + + if (options && options.username && options.accessKey) { + self._authString = options.username+":"+options.accessKey; + } + + self.protocol = {"direct":{}}; + self.commands = {"direct":{}}; + self.tests = {"direct":{}}; + self.assert = {"direct":{}}; + self.direct = {}; + self.custom = {}; + + function addDirectCommands(scope, commands) { + for(var command in commands) { + var method = commands[command]; + scope[command] = (function(method) { + return function() { + var args = Array.prototype.slice.call(arguments); + method.apply(self, args); + }; + })(method); + } + } + + var root = {children:[]}; + var currentQueueScope = root.children; + + function addQueueCommands(scope, directScope, commands) { + for(var commandName in commands) { + scope[commandName] = (function(internalCommandName) { + return function() { + var newQueueItem = new QueueItem(internalCommandName, directScope[internalCommandName], self, arguments); + self.currentQueueItem.add(newQueueItem); + + // when adding commands, we return the instance of the client to be able to chain + if (self.chain) { + return self; + } + }; + })(commandName); + } + } + + // this funciton is an entry point for adding new commands + this.addCommand = function(commandName, command) { + if (self[commandName]) { + throw "The command '" + commandName + "' is already defined!"; + } + + self[commandName] = (function(internalCommandName) + { + return function() { + var newQueueItem = new QueueItem(internalCommandName, command, self, arguments); + self.currentQueueItem.add(newQueueItem); + + // when adding commands, we return the instance of the client to be able to chain + if (self.chain) { + return self; + } + }; + })(commandName); + + return self; + }; + + // function for printing the queue, only used in development + function printQueueNow() { + printNewQueue(rootItem, 0); + } + + // creates a string when logging in development + function createString(sign, multiple) { + var result = ""; + for(var i = 0; i < multiple; i++) { + result += sign; + } + return (multiple > 0 ? multiple + " " : multiple) + result; + } + + // function for printing the queue, only used in development + function printNewQueue(q, l) { + var preString = createString("--", l); + + if (q) { + for(var i = 0; i < q.children.length; i++) { + if (self.currentQueueItem == q.children[i]) { + console.log(colors.dkgray + preString + colors.reset, colors.violet + q.children[i].commandName + colors.reset + " -> " + q.children[i].isDone); + } else { + console.log(colors.dkgray + preString + colors.reset, colors.green + q.children[i].commandName + colors.reset + " -> " + q.children[i].isDone); + } + printNewQueue(q.children[i], l + 1); + } + } + } + + var QueueItem = function(commandName, method, scope, args) + { + this.children = []; + this.commandName = commandName; + this.method = method; + this.arguments = args; + this.scope = scope; + this.currentChildIndex = 0; + this.isDone = false; + + var self = this; + + // change callback + this.arguments = []; + var hasCallback = false; + for(var i = 0, ii = args.length; i < ii; i++) { + var currentArg = args[i]; + if (typeof currentArg == "function" && i == (args.length - 1)) { + hasCallback = true; + this.arguments.push((function(method, methodName) { + return function(result) { + + // call the callback + method.call(scope, result); + + // console.log("NEXT IN CALLBACK", method.toString()) + // call the next item + self.next(); + + }; + })(currentArg, commandName) + ); + } else { + this.arguments.push(currentArg); + } + } + + if (!hasCallback) { + this.arguments.push((function() { + return function() { + // console.log("NEXT IN EMPTY CALLBACK") + // continue queue after callback + self.next(); + }; + })()); + } + }; + + // queue item run command + QueueItem.prototype.run = function() { + + // switch to the current queue item to make future addings to the correct queue item + self.currentQueueItem = this; + + // save the current length in case new items are added + var currentLength = this.children.length; + + // run the command + this.method.apply(this.scope, this.arguments); + + // if the command added new items to the queue, we make sure we run those commans + if (currentLength < this.children.length) { + //console.log("RUM") + this.next(); + } + }; + + // add queue item to the current item + QueueItem.prototype.add = function(item) { + // make a reference to its parent so we can travel back + item.parent = this; + + // add the new item to this childrens list + this.children.push(item); + + // if we arent running, its time now + if (!queueIsRunning) { + // make sure we switch the running flag so that we dont run .next again when a new item is added. + queueIsRunning = true; + + // begin the que + //console.log("ADD") + this.next(); + } else { + //console.log() + /* if(this.getNextChildToRun()) + { + queueIsRunning = true; + + this.next(); + }*/ + } + }; + + // go to next queu item + QueueItem.prototype.next = function() + { + + //printQueueNow(); + + // if we have more children, run the next + // otherwise tell the item we are done + if (this.currentChildIndex < this.children.length) + { + this.children[this.currentChildIndex].run(); + this.currentChildIndex++; + } + else + { + this.done(); + } + }; + + // the done method has to check if we are done for real, ie all children are done. + // if not, we check what children are left to run + QueueItem.prototype.done = function(scope) + { + if (!this.isDone) + { + // get the next undone child + var checkDoneChildren = this.getNextChildToRun(); + + // if its null, we know all children are done and we dont need to go further + if (checkDoneChildren == null) { + // mark this as done + this.isDone = true; + + // if we have a parent, run its next command, otherwise we are in the root and are totally finished + if (this.parent) { + // console.log("PARENT DONE") + this.parent.next(); + } else { + // and if we are finished we can turn off the running flag + queueIsRunning = false; + } + } else { + // but if there was one more child that wasnt ready, run it + // console.log("checkDoneChildren.next") + // checkDoneChildren.next(); + } + } else { + // if we are done, we when wheter everything in the queue is done. if so, set the running flag to false + var nextToRun = self.currentQueueItem.getNextChildToRun(); + if (nextToRun === null) { + queueIsRunning = false; + } + } + }; + + // recursive function to get the next undone item + QueueItem.prototype.getNextChildToRun = function() { + var notDone = null; + var done = true; + var child = null; + for(var i = 0, ii = this.children.length; i < ii; i++) { + + if (this.children[i] && !this.children[i].isDone) { + return this.children[i]; + } else { + child = this.children[i].getNextChildToRun(); + } + } + + return child; + }; + + // create the first item of the queue, ie the root + var rootItem = new QueueItem("root", "none", this, []); + + // mark it as the current context + self.currentQueueItem = rootItem; + + // expose protocol with correct context + addDirectCommands(self.direct, protocolCommands); + + // create queue commands for the protocol + addQueueCommands(self, protocolCommands, protocolCommands); + + + /* ------------------------ create commands ------------------------ */ + // expose protocol with correct context + // addDirectCommands(self.commands.direct, commandList); + + // create the commands + addQueueCommands(self, commandList, commandList); + + + /* ------------------------ create tests ------------------------ */ + // expose protocol with correct context + // addDirectCommands(self.tests.direct, testList); + + // create the commands + addQueueCommands(self.tests, testList, testList); + + addQueueCommands(self.assert, assertList, assertList); + + + + /*if (username && accessKey) { + var authString = username+":"+accessKey; + var buf = new Buffer(authString); + this.options['headers'] = { + 'Authorization': 'Basic '+ buf.toString('base64') + } + this.desiredCapabilities.platform = "VISTA"; + }*/ + if (self.logLevel !== 'silent' && !infoHasBeenShown) { + console.log(""); + console.log(colors.yellow + "=====================================================================================" + colors.reset); + console.log(""); + console.log("Selenium 2.0/webdriver protocol bindings implementation with helper commands in nodejs by Camilo Tapia."); + console.log("For a complete list of commands, visit " + colors.lime + "http://code.google.com/p/selenium/wiki/JsonWireProtocol" + colors.reset + ". "); + console.log("Not all commands are implemented yet. visit " + colors.lime + "https://github.com/Camme/webdriverjs" + colors.reset + " for more info on webdriverjs. "); + //Start with " + colors.lime + "-h option" + colors.reset + " to get a list of all commands."); + console.log(""); + console.log(colors.yellow + "=====================================================================================" + colors.reset); + console.log(""); + infoHasBeenShown = true; + } + + // create a set of request options + self.createOptions = function(requestOptions) { + var newOptions = self.extend(defaultOptions, requestOptions); + var path = startPath; + + if (self.sessionId) { + newOptions.path = newOptions.path.replace(':sessionId', self.sessionId); + } + + if (newOptions.path && newOptions.path !== "") { + path += newOptions.path; + } + + newOptions.path = path; + + return newOptions; + }; + + self.setScreenshotPath = function(pathToSaveTo) { + self.screenshotPath = pathToSaveTo; + return self; + }; + +}; + +// send the protocol command to the webdriver server +WebdriverJs.prototype.executeProtocolCommand = function(requestOptions, callback, data) { + var request = this.createRequest(requestOptions, data, callback); + var stringData = JSON.stringify(data); + + if (this.logLevel === 'verbose' && stringData != "{}") + { + this.log(colors.brown + "DATA\t\t " + colors.reset + stringData); + } + + request.write(stringData); + request.end(); +}; + + +// a basic extend method +WebdriverJs.prototype.extend = function(base, obj) { + var newObj = {}; + for(var prop1 in base) + { + newObj[prop1] = base[prop1]; + } + for(var prop2 in obj) + { + newObj[prop2] = obj[prop2]; + } + return newObj; +}; + + +WebdriverJs.prototype.testMode = function() { + this.log(colors.yellow + "NOW IN TEST MODE!" + colors.reset + "\n"); + this.logLevel = 'silent'; + return this; +}; + +WebdriverJs.prototype.silent = function() { + this.logLevel = 'silent'; + return this; +}; + +WebdriverJs.prototype.noChain = function() { + this.chain = false; +}; + + + +// strip the content from unwanted characters +WebdriverJs.prototype.strip = function(str) { + var x = [], + i = 0, + il = str.length; + + for(i; i < il; i++){ + if (str.charCodeAt(i)) + { + x.push(str.charAt(i)); + } + } + + return x.join(''); +}; + + + + +// A log helper with fancy colors +WebdriverJs.prototype.log = function(message, content) { + if(this.logLevel !== 'verbose'){ + return false; + } + + var currentDate = new Date(); + var dateString = currentDate.toString().match(/\d\d:\d\d:\d\d/)[0]; + + if (!content) + { + console.log(colors.dkgray + "[" + dateString + "]: " + colors.reset, message); + } + else + { + console.log(colors.dkgray +"[" + dateString + "]: " + colors.reset, message, "\t", JSON.stringify(content)); + } + +}; + + +// a helper function to create a callback that doesnt return anything +WebdriverJs.prototype.proxyResponseNoReturn = function(callback) { + return function(response) + { + if (callback) { + callback(); + } + }; +}; + + +WebdriverJs.prototype.createRequest = function(requestOptions, data, callback) { + + if (typeof data == "function") { + callback = data; + data = ""; + } + + var fullRequestOptions = this.createOptions(requestOptions); + + this.log(colors.violet + "COMMAND\t" + colors.reset + fullRequestOptions.method, fullRequestOptions.path); + + fullRequestOptions.headers = { + 'content-type': 'application/json', + 'charset': 'charset=UTF-8' + }; + if(this._authString){ + var buf = new Buffer(this._authString); + fullRequestOptions.headers.Authorization = 'Basic '+ buf.toString('base64'); + } + + // we need to set the requests content-length. either from the data that is sent or 0 if nothing is sent + if (data !== "") { + fullRequestOptions.headers['content-length'] = JSON.stringify(data).length; + } else { + fullRequestOptions.headers['content-length'] = 0; + } + + var request = http.request(fullRequestOptions, callback); + + var self = this; + request.on("error", function(err) { + self.log(colors.red + "ERROR ON REQUEST" + colors.reset); + console.log(colors.red, err, colors.reset); + }); + + return request; +}; + + +// a helper function to create a callback that parses and checks the result +WebdriverJs.prototype.proxyResponse = function(callback, options) { + + var self = this; + var baseOptions = { saveScreenshotOnError: true}; + return function(response) { + response.setEncoding('utf8'); + + var data = ""; + response.on('data', function(chunk) { data += chunk.toString(); }); + + response.on('end', function() { + if (options) { + if (options.setSessionId) { + try { + var locationList = response.headers.location.split("/"); + var sessionId = locationList[locationList.length - 1]; + self.sessionId = sessionId; + self.log("SET SESSION ID ", sessionId); + } + catch(err) { + self.log(colors.red + "COULDNT GET A SESSION ID" + colors.reset); + } + + } + } + + var result; + + try { + result = JSON.parse(self.strip(data)); + } + catch (err) { + if (data !== "") { + self.log("/n" + colors.red + err + colors.reset + "/n"); + self.log(colors.dkgrey + data + colors.reset + "/n"); + } + result = {value: -1}; + + if (callback) { + callback(result); + } + + return; + } + + + if (result.status === 0) { + self.log(colors.teal + "RESULT\t" + colors.reset, result.value); + } + else if (result.status === 7) { + result = {value: -1, status: result.status, orgStatus: result.status, orgStatusMessage: errorCodes[result.status].message}; + self.log(colors.teal + "RESULT\t" + colors.reset, errorCodes[result.status].id); + } + else if (result.status === 11) { + result = {value: -1, error: errorCodes[result.status].id, status: result.status, orgStatus: result.status, orgStatusMessage: errorCodes[result.status].message}; + self.log(colors.teal + "RESULT\t" + colors.reset, errorCodes[result.status].id); + } + else { + + // remove the content of the screenshot temporarily so that cthe consle output isnt flooded + var screenshotContent = result.value.screen; + delete result.value.screen; + if (errorCodes[result.status]) { + self.log(colors.red + "ERROR\t" + colors.reset + "" + errorCodes[result.status].id + "\t" + errorCodes[result.status].message); + + } + else { + self.log(colors.red + "ERROR\t" + colors.reset + "\t", result + "\t" + errorCodes["-1"].message); + } + + try { + var jsonData = JSON.parse(self.strip(data)); + self.log("\t\t" + jsonData.value.message); + } + catch(err) { + self.log("\t\t" + data); + } + + + // add the screenshot again + result.value.screen = screenshotContent; + if (process.argv.length > 1) { + + var runner = process.argv[1].replace(/\.js/gi, ""); + + var prePath = ""; + + if (self.screenshotPath === "") { + prePath = runner; + } + else { + prePath = self.screenshotPath + runner.substring(runner.lastIndexOf("/") + 1); + } + + // dont save the screenshot if its an unknown error + if (result.status != 13) { + var errorScreenshotFileName = prePath + "-ERROR.AT." + self.currentQueueItem.commandName + ".png"; + self.log(colors.red + "SAVING SCREENSHOT WITH FILENAME:" + colors.reset); + self.log(colors.brown + errorScreenshotFileName + colors.reset); + self.saveScreenshotToFile(errorScreenshotFileName, result.value.screen); + } + } + } + + if (!self.sessionId) { + self.log(colors.red + "NO SESSION, EXITING" + colors.reset); + process.exit(1); + } + + if (callback) { + // console.log("run callback for protocol") + callback(result); + } + } + ); + }; +}; + +// log test result +WebdriverJs.prototype.showTest = function(theTest, receivedValue, expectedValue, message) { + if (theTest) { + console.log(colors.green + "✔" + colors.reset + "\t" + message); + } else { + console.log(colors.red + "✖" + colors.reset + "\t" + message + "\t" + colors.white + expectedValue + colors.reset + " !== " + colors.red + receivedValue + colors.reset); + } +}; + + + +WebdriverJs.prototype.saveScreenshotToFile = function(fileName, data) +{ + //console.log(fileName) + // var buff = new Buffer(data, "binary"); + // console.log(data) + fs.writeFile(fileName, data, "base64", function(err) { + if (err) { + this.log(err); + } + }); +}; + + + +// the acutal commands. read them dynamicaly +var protocolFiles = fs.readdirSync(__dirname + "/protocol/"); +var protocolCommands = {}; + +for(var i = 0, ii = protocolFiles.length; i < ii; i++) +{ + if (path.extname(protocolFiles[i]) == ".js") + { + var commandName = path.basename(protocolFiles[i], '.js'); + protocolCommands[commandName] = require("./protocol/" + protocolFiles[i]).command; + } +} + + +/* +// ------------------ tests helpers ---------------- +var testFiles = fs.readdirSync(__dirname + "/tests/"); +for(var i = 0, ii = testFiles.length; i < ii; i++) +{ + var commandName = path.basename(testFiles[i], '.js'); + WebdriverJs.prototype[commandName] = require("./tests/" + testFiles[i]).command; +} +*/ +// save the command list to a variable available to all + + + + + + +var commandFiles = fs.readdirSync(__dirname + "/commands/"); +var commandList = {}; + +for(var i = 0, ii = commandFiles.length; i < ii; i++) { + if (path.extname(commandFiles[i]) == ".js") { + var commandName = path.basename(commandFiles[i], '.js'); + commandList[commandName] = require("./commands/" + commandFiles[i]).command; + } +} + + +var testFiles = fs.readdirSync(__dirname + "/tests/"); +var testList = {}; + +for(var i = 0, ii = testFiles.length; i < ii; i++) { + if (path.extname(testFiles[i]) == ".js") { + var commandName = path.basename(testFiles[i], '.js'); + testList[commandName] = require("./tests/" + testFiles[i]).command; + } +} + + +var assertFiles = fs.readdirSync(__dirname + "/asserts/"); +var assertList = {}; +for(var i = 0, ii = assertFiles.length; i < ii; i++) { + if (path.extname(assertFiles[i]) == ".js") { + var commandName = path.basename(assertFiles[i], '.js'); + assertList[commandName] = require("./asserts/" + assertFiles[i]).command; + } +} + + + +var singletonInstance = null; + +// expose the man function +// if we need a singleton, we provide the option here +exports.remote = function(options)//host, port, username, pass) +{ + // make sure we have a default options if none are provided + options = options || {}; + + if (options.singleton) { + if (!singletonInstance) { + singletonInstance = new WebdriverJs(options); + } + return singletonInstance; + } else { + return new WebdriverJs(options);//host, port, username, pass); + } +}; diff --git a/node_modules/webdriverjs/lib/webdriverjs.js b/node_modules/webdriverjs/lib/webdriverjs.js deleted file mode 100644 index aa433f0bf30..00000000000 --- a/node_modules/webdriverjs/lib/webdriverjs.js +++ /dev/null @@ -1,912 +0,0 @@ -// this is my take on a client for the webdriver -// its totally inspired by jellyfishs webdriver, but my goal is to make all the webdriver protocol items available, as near the original as possible - -var http = require("http"); -var fs = require('fs'); -var path = require('path'); -var infoHasBeenShown = false; - -// useful colors for bash -var colors = { - black: "\x1b[0;30m", - dkgray: "\x1b[1;30m", - brick: "\x1b[0;31m", - red: "\x1b[1;31m", - green: "\x1b[0;32m", - lime: "\x1b[1;32m", - brown: "\x1b[0;33m", - yellow: "\x1b[1;33m", - navy: "\x1b[0;34m", - blue: "\x1b[1;34m", - violet: "\x1b[0;35m", - magenta: "\x1b[1;35m", - teal: "\x1b[0;36m", - cyan: "\x1b[1;36m", - ltgray: "\x1b[0;37m", - white: "\x1b[1;37m", - reset: "\x1b[0m" -}; - -var errorCodes = { - "-1": {id: "Unknown", message: "Remote end send an unknown status code."}, - "0": {id: "Success", message: "The command executed successfully."}, - "7": {id: "NoSuchElement", message: "An element could not be located on the page using the given search parameters."}, - "8": {id: "NoSuchFrame", message: "A request to switch to a frame could not be satisfied because the frame could not be found."}, - "9": {id: "UnknownCommand", message: "The requested resource could not be found, or a request was received using an HTTP method that is not supported by the mapped resource."}, - "10": {id: "StaleElementReference", message: "An element command failed because the referenced element is no longer attached to the DOM."}, - "11": {id: "ElementNotVisible", message: "An element command could not be completed because the element is not visible on the page."}, - "12": {id: "InvalidElementState", message: "An element command could not be completed because the element is in an invalid state (e.g. attempting to click a disabled element)."}, - "13": {id: "UnknownError", message: "An unknown server-side error occurred while processing the command."}, - "15": {id: "ElementIsNotSelectable", message: "An attempt was made to select an element that cannot be selected."}, - "17": {id: "JavaScriptError", message: "An error occurred while executing user supplied JavaScript."}, - "19": {id: "XPathLookupError", message: "An error occurred while searching for an element by XPath."}, - "23": {id: "NoSuchWindow", message: "A request to switch to a different window could not be satisfied because the window could not be found."}, - "24": {id: "InvalidCookieDomain", message: "An illegal attempt was made to set a cookie under a different domain than the current page."}, - "25": {id: "UnableToSetCookie", message: "A request to set a cookie's value could not be satisfied."}, - "26": {id: "UnexpectedAlertOpen", message: "A modal dialog was open, blocking this operation"}, - "27": {id: "NoAlertOpenError", message: "An attempt was made to operate on a modal dialog when one was not open."}, - "28": {id: "ScriptTimeout", message: "A script did not complete before its timeout expired."}, - "29": {id: "InvalidElementCoordinates", message: "The coordinates provided to an interactions operation are invalid."}, - "30": {id: "IMENotAvailable", message: "IME was not available."}, - "31": {id : "IMEEngineActivationFailed", message: "An IME engine could not be started."}, - "32": {id: "InvalidSelector", message: "Argument was an invalid selector (e.g. XPath/CSS)."}, - "34": {id: "ElementNotScrollable", message: "Element cannot be scrolled into view."} -}; - - -var WebdriverJs = function(options)//host, port, username, pass) -{ - - options = options || {}; - - var self = this, - startPath = '/wd/hub', - queue = [], - queueIsRunning = false; - - self.chain = true; - self.sessionId = null; - self.queuedPaused = false; - - /* log level - * silent : no logs - * command : command only - * verbose : command + data - */ - self.logLevel = options.logLevel || 'verbose'; - - // where to save the screenshots. default to current folder - self.screenshotPath = ""; - - var defaultOptions = { - host: options.host || 'localhost', - port: options.port || 4444, - method: 'POST' - }; - - // defaultOptions = self.extend(defaultOptions, options); - - self.desiredCapabilities = { - browserName: "firefox", - version: "", - javascriptEnabled: true, - platform: "ANY" - }; - - if (options.desiredCapabilities) - { - self.desiredCapabilities = self.extend(self.desiredCapabilities, options.desiredCapabilities); - } - if (options && options.username && options.accessKey) { - self._authString = options.username+":"+options.accessKey; - } - - self.protocol = {"direct":{}}; - self.commands = {"direct":{}}; - self.tests = {"direct":{}}; - self.assert = {"direct":{}}; - self.direct = {}; - self.custom = {}; - - function addDirectCommands(scope, commands) - { - for(var command in commands) - { - var method = commands[command]; - scope[command] = (function(method) - { - return function() - { - var args = Array.prototype.slice.call(arguments); - method.apply(self, args); - }; - })(method); - } - } - - var root = {children:[]}; - var currentQueueScope = root.children; - - function addQueueCommands(scope, directScope, commands) - { - for(var commandName in commands) - { - scope[commandName] = (function(internalCommandName) - { - return function() - { - var newQueueItem = new QueueItem(internalCommandName, directScope[internalCommandName], self, arguments); - self.currentQueueItem.add(newQueueItem); - - // when adding commands, we return the instance of the client to be able to chain - if (self.chain) - { - return self; - } - }; - })(commandName); - } - } - - // this funciton is an entry point for adding new commands - this.addCommand = function(commandName, command) - { - if (self[commandName]) - { - throw "The command '" + commandName + "' is already defined!"; - } - - self[commandName] = (function(internalCommandName) - { - return function() - { - var newQueueItem = new QueueItem(internalCommandName, command, self, arguments); - self.currentQueueItem.add(newQueueItem); - - // when adding commands, we return the instance of the client to be able to chain - if (self.chain) - { - return self; - } - }; - })(commandName); - - return self; - } - - // function for printing the queue, only used in development - function printQueueNow() - { - console.log("") - printNewQueue(rootItem, 0); - } - - // creates a string when logging in development - function createString(sign, multiple) - { - var result = ""; - for(var i = 0; i < multiple; i++) - { - result += sign; - } - return (multiple > 0 ? multiple + " " : multiple) + result; - } - - // function for printing the queue, only used in development - function printNewQueue(q, l) - { - var preString = createString("--", l); - - if (q) - { - for(var i = 0; i < q.children.length; i++) - { - if (self.currentQueueItem == q.children[i]) - { - console.log(colors.dkgray + preString + colors.reset, colors.violet + q.children[i].commandName + colors.reset + " -> " + q.children[i].isDone); - } - else - { - console.log(colors.dkgray + preString + colors.reset, colors.green + q.children[i].commandName + colors.reset + " -> " + q.children[i].isDone); - } - printNewQueue(q.children[i], l + 1); - } - } - } - - var QueueItem = function(commandName, method, scope, args) - { - this.children = []; - this.commandName = commandName; - this.method = method; - this.arguments = args; - this.scope = scope; - this.currentChildIndex = 0; - this.isDone = false; - - var self = this; - - // change callback - this.arguments = []; - var hasCallback = false; - for(var i = 0, ii = args.length; i < ii; i++) - { - var currentArg = args[i]; - if (typeof currentArg == "function" && i == (args.length - 1)) - { - hasCallback = true; - this.arguments.push((function(method, methodName) - { - return function(result) - { - - // call the callback - method.call(scope, result); - - // console.log("NEXT IN CALLBACK", method.toString()) - // call the next item - self.next(); - - }; - })(currentArg, commandName) - ); - } - else - { - this.arguments.push(currentArg); - } - } - - if (!hasCallback) - { - this.arguments.push((function(){ - return function() - { -// console.log("NEXT IN EMPTY CALLBACK") - // continue queue after callback - self.next(); - }; - })()); - } - - }; - - - - - - - - // queue item run command - QueueItem.prototype.run = function() - { - - // switch to the current queue item to make future addings to the correct queue item - self.currentQueueItem = this; - - // save the current length in case new items are added - var currentLength = this.children.length; - - // run the command - this.method.apply(this.scope, this.arguments); - - // if the command added new items to the queue, we make sure we run those commans - if (currentLength < this.children.length) - { - //console.log("RUM") - this.next(); - } - - }; - - // add queue item to the current item - QueueItem.prototype.add = function(item) - { - - // make a reference to its parent so we can travel back - item.parent = this; - - // add the new item to this childrens list - this.children.push(item); - - // if we arent running, its time now - if (!queueIsRunning) - { - // make sure we switch the running flag so that we dont run .next again when a new item is added. - queueIsRunning = true; - - // begin the que - //console.log("ADD") - this.next(); - } - else - { - //console.log() - /* if(this.getNextChildToRun()) - { - queueIsRunning = true; - - this.next(); - }*/ - } - - - - }; - - // go to next queu item - QueueItem.prototype.next = function() - { - - //printQueueNow(); - - // if we have more children, run the next - // otherwise tell the item we are done - if (this.currentChildIndex < this.children.length) - { - this.children[this.currentChildIndex].run(); - this.currentChildIndex++; - } - else - { - this.done(); - } - }; - - // the done method has to check if we are done for real, ie all children are done. - // if not, we check what children are left to run - QueueItem.prototype.done = function(scope) - { - if (!this.isDone) - { - // get the next undone child - var checkDoneChildren = this.getNextChildToRun(); - - // if its null, we know all children are done and we dont need to go further - if (checkDoneChildren == null) - { - // mark this as done - this.isDone = true; - - // if we have a parent, run its next command, otherwise we are in the root and are totally finished - if (this.parent) - { - // console.log("PARENT DONE") - this.parent.next(); - } - else - { - // and if we are finished we can turn off the running flag - queueIsRunning = false; - } - } - else - { - // but if there was one more child that wasnt ready, run it - // console.log("checkDoneChildren.next") - //checkDoneChildren.next(); - } - } - else - { - - // if we are done, we when wheter everything in the queue is done. if so, set the running flag to false - var nextToRun = self.currentQueueItem.getNextChildToRun(); - if (nextToRun === null) - { - queueIsRunning = false; - } - } - - }; - - // recursive function to get the next undone item - QueueItem.prototype.getNextChildToRun = function() - { - var notDone = null; - var done = true; - var child = null; - for(var i = 0, ii = this.children.length; i < ii; i++) - { - - if (this.children[i] && !this.children[i].isDone) - { - return this.children[i]; - } - else - { - child = this.children[i].getNextChildToRun(); - } - - } - - return child; - - }; - - // create the first item of the queue, ie the root - var rootItem = new QueueItem("root", "none", this, []); - - // mark it as the current context - self.currentQueueItem = rootItem; - - - // expose protocol with correct context - addDirectCommands(self.direct, protocolCommands); - - // create queue commands for the protocol - addQueueCommands(self, protocolCommands, protocolCommands); - - - /* ------------------------ create commands ------------------------ */ - // expose protocol with correct context - // addDirectCommands(self.commands.direct, commandList); - - // create the commands - addQueueCommands(self, commandList, commandList); - - - /* ------------------------ create tests ------------------------ */ - // expose protocol with correct context - // addDirectCommands(self.tests.direct, testList); - - // create the commands - addQueueCommands(self.tests, testList, testList); - - addQueueCommands(self.assert, assertList, assertList); - - - - /*if (username && accessKey) { - var authString = username+":"+accessKey; - var buf = new Buffer(authString); - this.options['headers'] = { - 'Authorization': 'Basic '+ buf.toString('base64') - } - this.desiredCapabilities.platform = "VISTA"; - }*/ - - if (self.logLevel !== 'silent' && !infoHasBeenShown) - { - console.log(""); - console.log(colors.yellow + "=====================================================================================" + colors.reset); - console.log(""); - console.log("Selenium 2.0/webdriver protocol bindings implementation with helper commands in nodejs by Camilo Tapia."); - console.log("For a complete list of commands, visit " + colors.lime + "http://code.google.com/p/selenium/wiki/JsonWireProtocol" + colors.reset + ". "); - console.log("Not all commands are implemented yet. visit " + colors.lime + "https://github.com/Camme/webdriverjs" + colors.reset + " for more info on webdriverjs. "); - //Start with " + colors.lime + "-h option" + colors.reset + " to get a list of all commands."); - console.log(""); - console.log(colors.yellow + "=====================================================================================" + colors.reset); - console.log(""); - - infoHasBeenShown = true; - } - - // create a set of request options - self.createOptions = function(requestOptions) - { - - var newOptions = self.extend(defaultOptions, requestOptions); - - - var path = startPath; - - if (self.sessionId) - { - newOptions.path = newOptions.path.replace(':sessionId', self.sessionId); - } - - if (newOptions.path && newOptions.path !== "") - { - path += newOptions.path; - } - - newOptions.path = path; - - return newOptions; - }; - - - self.setScreenshotPath = function(pathToSaveTo) - { - self.screenshotPath = pathToSaveTo; - return self; - } - - -// console.log(process.argv) - -}; - -// send the protocol command to the webdriver server -WebdriverJs.prototype.executeProtocolCommand = function(requestOptions, callback, data) -{ - var request = this.createRequest(requestOptions, data, callback); - var stringData = JSON.stringify(data); - - if (this.logLevel === 'verbose' && stringData != "{}") - { - this.log(colors.brown + "DATA\t\t " + colors.reset + stringData); - } - - request.write(stringData); - request.end(); -}; - - -// a basic extend method -WebdriverJs.prototype.extend = function(base, obj) -{ - var newObj = {}; - for(var prop1 in base) - { - newObj[prop1] = base[prop1]; - } - for(var prop2 in obj) - { - newObj[prop2] = obj[prop2]; - } - return newObj; -}; - - -WebdriverJs.prototype.testMode = function() -{ - this.log(colors.yellow + "NOW IN TEST MODE!" + colors.reset + "\n"); - this.logLevel = 'silent'; - return this; -}; - -WebdriverJs.prototype.silent = function() -{ - this.logLevel = 'silent'; - return this; -}; - -WebdriverJs.prototype.noChain = function() -{ - this.chain = false; -}; - - - -// strip the content from unwanted characters -WebdriverJs.prototype.strip = function(str) -{ - var x = [], - i = 0, - il = str.length; - - for(i; i < il; i++){ - if (str.charCodeAt(i)) - { - x.push(str.charAt(i)); - } - } - - return x.join(''); -}; - - - - -// A log helper with fancy colors -WebdriverJs.prototype.log = function(message, content) -{ - if(this.logLevel !== 'verbose'){ - return false; - } - - var currentDate = new Date(); - var dateString = currentDate.toString().match(/\d\d:\d\d:\d\d/)[0]; - - if (!content) - { - console.log(colors.dkgray + "[" + dateString + "]: " + colors.reset, message); - } - else - { - console.log(colors.dkgray +"[" + dateString + "]: " + colors.reset, message, "\t", JSON.stringify(content)); - } - -}; - - -// a helper function to create a callback that doesnt return anything -WebdriverJs.prototype.proxyResponseNoReturn = function(callback) -{ - return function(response) - { - if (callback) - { - callback(); - } - }; -}; - - -WebdriverJs.prototype.createRequest = function(requestOptions, data, callback) -{ - if (typeof data == "function") - { - callback = data; - data = ""; - } - - var fullRequestOptions = this.createOptions(requestOptions); - - this.log(colors.violet + "COMMAND\t" + colors.reset + fullRequestOptions.method, fullRequestOptions.path); - - fullRequestOptions.headers = { - 'content-type': 'application/json', - 'charset': 'charset=UTF-8' - } - if(this._authString){ - var buf = new Buffer(this._authString); - fullRequestOptions.headers.Authorization = 'Basic '+ buf.toString('base64'); - } - - // we need to set the requests content-length. either from the data that is sent or 0 if nothing is sent - if (data != "") - { - fullRequestOptions.headers['content-length'] = JSON.stringify(data).length; - } - else - { - fullRequestOptions.headers['content-length'] = 0; - } - - var request = http.request(fullRequestOptions, callback); - - var self = this; - request.on("error", function(err) - { - self.log(colors.red + "ERROR ON REQUEST" + colors.reset); - console.log(colors.red, err, colors.reset); - }); - - return request; -}; - - -// a helper function to create a callback that parses and checks the result -WebdriverJs.prototype.proxyResponse = function(callback, options) { - - var self = this; - var baseOptions = { saveScreenshotOnError: true}; - return function(response) { - response.setEncoding('utf8'); - - var data = ""; - response.on('data', function(chunk) { data += chunk.toString(); }); - - response.on('end', function() { - if (options) { - if (options.setSessionId) { - try { - var locationList = response.headers.location.split("/"); - var sessionId = locationList[locationList.length - 1]; - self.sessionId = sessionId; - self.log("SET SESSION ID ", sessionId); - } - catch(err) { - self.log(colors.red + "COULDNT GET A SESSION ID" + colors.reset); - } - - } - } - - var result; - - try { - result = JSON.parse(self.strip(data)); - } - catch (err) { - if (data !== "") { - self.log("/n" + colors.red + err + colors.reset + "/n"); - self.log(colors.dkgrey + data + colors.reset + "/n"); - } - result = {value: -1}; - - if (callback) { - callback(result); - } - - return; - } - - - if (result.status === 0) { - self.log(colors.teal + "RESULT\t" + colors.reset, result.value); - } - else if (result.status === 7) { - result = {value: -1, status: result.status, orgStatus: result.status, orgStatusMessage: errorCodes[result.status].message}; - self.log(colors.teal + "RESULT\t" + colors.reset, errorCodes[result.status].id); - } - else if (result.status === 11) { - result = {value: -1, error: errorCodes[result.status].id, status: result.status, orgStatus: result.status, orgStatusMessage: errorCodes[result.status].message}; - self.log(colors.teal + "RESULT\t" + colors.reset, errorCodes[result.status].id); - } - else { - - // remove the content of the screenshot temporarily so that cthe consle output isnt flooded - var screenshotContent = result.value.screen; - delete result.value.screen; - if (errorCodes[result.status]) { - self.log(colors.red + "ERROR\t" + colors.reset + "" + errorCodes[result.status].id + "\t" + errorCodes[result.status].message); - - } - else { - self.log(colors.red + "ERROR\t" + colors.reset + "\t", result + "\t" + errorCodes["-1"].message); - } - - try { - var jsonData = JSON.parse(self.strip(data)); - self.log("\t\t" + jsonData.value.message); - } - catch(err) { - self.log("\t\t" + data); - } - - - // add the screenshot again - result.value.screen = screenshotContent; - if (process.argv.length > 1) { - - var runner = process.argv[1].replace(/\.js/gi, ""); - - var prePath = ""; - - if (self.screenshotPath === "") { - prePath = runner; - } - else { - prePath = self.screenshotPath + runner.substring(runner.lastIndexOf("/") + 1); - } - - // dont save the screenshot if its an unknown error - if (result.status != 13) { - var errorScreenshotFileName = prePath + "-ERROR.AT." + self.currentQueueItem.commandName + ".png"; - self.log(colors.red + "SAVING SCREENSHOT WITH FILENAME:" + colors.reset); - self.log(colors.brown + errorScreenshotFileName + colors.reset); - self.saveScreenshotToFile(errorScreenshotFileName, result.value.screen); - } - } - } - - if (!self.sessionId) { - self.log(colors.red + "NO SESSION, EXITING" + colors.reset) - process.exit(1); - } - - if (callback) { - // console.log("run callback for protocol") - callback(result); - } - } - ); - }; -}; - -// log test result -WebdriverJs.prototype.showTest = function(theTest, receivedValue, expectedValue, message) { - if (theTest) - { - console.log(colors.green + "✔" + colors.reset + "\t" + message); - } - else - { - console.log(colors.red + "✖" + colors.reset + "\t" + message + "\t" + colors.white + expectedValue + colors.reset + " !== " + colors.red + receivedValue + colors.reset); - } -}; - - - -WebdriverJs.prototype.saveScreenshotToFile = function(fileName, data) -{ -//console.log(fileName) -// var buff = new Buffer(data, "binary"); -// console.log(data) - fs.writeFile(fileName, data, "base64", function(err) - { - if (err) - { - this.log(err); - } - } - ); -} - - - -// the acutal commands. read them dynamicaly -var protocolFiles = fs.readdirSync(__dirname + "/protocol/"); -var protocolCommands = {}; - -for(var i = 0, ii = protocolFiles.length; i < ii; i++) -{ - if (path.extname(protocolFiles[i]) == ".js") - { - var commandName = path.basename(protocolFiles[i], '.js'); - protocolCommands[commandName] = require("./protocol/" + protocolFiles[i]).command; - } -} - - -/* -// ------------------ tests helpers ---------------- -var testFiles = fs.readdirSync(__dirname + "/tests/"); -for(var i = 0, ii = testFiles.length; i < ii; i++) -{ - var commandName = path.basename(testFiles[i], '.js'); - WebdriverJs.prototype[commandName] = require("./tests/" + testFiles[i]).command; -} -*/ -// save the command list to a variable available to all - - - - - - -var commandFiles = fs.readdirSync(__dirname + "/commands/"); -var commandList = {}; - -for(var i = 0, ii = commandFiles.length; i < ii; i++) -{ - if (path.extname(commandFiles[i]) == ".js") - { - var commandName = path.basename(commandFiles[i], '.js'); - commandList[commandName] = require("./commands/" + commandFiles[i]).command; - } -} - - -var testFiles = fs.readdirSync(__dirname + "/tests/"); -var testList = {}; - -for(var i = 0, ii = testFiles.length; i < ii; i++) -{ - if (path.extname(testFiles[i]) == ".js") - { - var commandName = path.basename(testFiles[i], '.js'); - testList[commandName] = require("./tests/" + testFiles[i]).command; - } -} - - -var assertFiles = fs.readdirSync(__dirname + "/asserts/"); -var assertList = {}; -for(var i = 0, ii = assertFiles.length; i < ii; i++) -{ - if (path.extname(assertFiles[i]) == ".js") - { - var commandName = path.basename(assertFiles[i], '.js'); - assertList[commandName] = require("./asserts/" + assertFiles[i]).command; - } -} - - - -var singletonInstance = null; - -// expose the man function -// if we need a singleton, we provide the option here -exports.remote = function(options)//host, port, username, pass) -{ - // make sure we have a default options if none are provided - options = options || {}; - - if (options.singleton) - { - if (!singletonInstance) - { - singletonInstance = new WebdriverJs(options); - } - return singletonInstance; - } - else - { - return new WebdriverJs(options);//host, port, username, pass); - } -}; diff --git a/node_modules/webdriverjs/package.json b/package.json similarity index 61% rename from node_modules/webdriverjs/package.json rename to package.json index a7a34760152..8563ba02a09 100644 --- a/node_modules/webdriverjs/package.json +++ b/package.json @@ -1,17 +1,12 @@ { "name": "webdriverjs", "description": "A nodejs bindings implementation for selenium 2.0/webdriver", - "tags": [ - "web", - "test", - "selenium", - "browser", - "javascript" - ], - "version": "0.6.9", + "version": "0.7", + "homepage": "https://github.com/Camme/webdriverjs", "author": "camilo tapia ", "contributors": [ - "Dan Jenkins " + "Dan Jenkins ", + "Christian Bromann " ], "repository": { "type": "git", @@ -20,19 +15,29 @@ "bugs": { "url": "https://github.com/Camme/webdriverjs/issues" }, - "engines": [ - "node" + "licenses": [ + { + "type": "MIT", + "url": "https://github.com/Camme/webdriverjs/blob/master/LICENSE-MIT" + } ], "main": "./lib/webdriverjs", - "dependencies": {}, - "directories": { - "lib": "./lib" + "engines": { + "node": ">= 0.8.0" }, + "dependencies": {}, + "devDependencies": {}, + "optionalDependencies": {}, + "tags": [ + "web", + "test", + "selenium", + "browser", + "javascript" + ], "keywords": [ "webdriverjs", "selenium", "saucelabs" ], - "devDependencies": {}, - "optionalDependencies": {} } diff --git a/readme.md b/readme.md index 56ad1b8e42d..18dbf872b98 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,5 @@ Webdriver/selenium 2.0 javascript bindings for nodejs -=== +===================================================== A WebDriver module for nodejs. Either use the super easy help commands or use the base Webdriver wire protocol commands. @@ -15,116 +15,130 @@ The two main reasons for this projects are: Either download it from github or use npm: - npm install webdriverjs +```shell +npm install webdriverjs +``` ### Example of webdriver with queued commands locally: Run selenium server first: - - java -jar selenium-server-standalone-2.11.0.jar - -Then run this with nodejs: - var webdriverjs = require("webdriverjs"); - var client = webdriverjs.remote(); - //var client = webdriverjs.remote({host: "xx.xx.xx.xx"}); // to run it on a remote webdriver/selenium server - //var client = webdriverjs.remote({desiredCapabilities:{browserName:"chrome"}}); // to run in chrome +```shell +java -jar selenium-server-standalone-2.11.0.jar +``` + +Then run this with nodejs: - client - .init() - .url("https://github.com/") - .getElementSize("id", "header", function(result){ console.log(result); }) - .getTitle(function(title) { console.log(title) }) - .getElementCssProperty("id", "header", "color", function(result){ console.log(result); }) - .end(); +```js +var webdriverjs = require("webdriverjs"); +var client = webdriverjs.remote(); +//var client = webdriverjs.remote({host: "xx.xx.xx.xx"}); // to run it on a remote webdriver/selenium server +//var client = webdriverjs.remote({desiredCapabilities:{browserName:"chrome"}}); // to run in chrome + +client + .init() + .url("https://github.com/") + .getElementSize("id", "header", function(result){ console.log(result); }) + .getTitle(function(title) { console.log(title) }) + .getElementCssProperty("id", "header", "color", function(result){ console.log(result); }) + .end(); +``` ### Submitting a form To submit a form, pick any elemtn inside the form (or the form itself) and call .submitForm - var client = require("webdriverjs").remote(); - - client - .init() - .url("http://www.google.com") - .setValue("#lst-ib", "webdriver") - .submitForm("#tsf") - .end(); +```js +var client = require("webdriverjs").remote(); +client + .init() + .url("http://www.google.com") + .setValue("#lst-ib", "webdriver") + .submitForm("#tsf") + .end(); +``` - -More examples in the examples folder +More examples in the examples folder. ### Other options To make webdriverjs be silent (omit all logs): - var client = require("webdriverjs").remote({logLevel: 'silent'}); // if you use it as part of other app and the logs arent interesting +```js +var client = require("webdriverjs").remote({logLevel: 'silent'}); // if you use it as part of other app and the logs arent interesting - client - .init() - .url("https://github.com/") - .getTitle( - function(result) - { - console.log(result) - } - ) - .end(); +client + .init() + .url("https://github.com/") + .getTitle( + function(result) + { + console.log(result) + } + ) + .end(); +``` ### Extending If you want to extend with your own set of commands there is a method called addCommand: - var client = require("webdriverjs").remote(); +```js +var client = require("webdriverjs").remote(); - // create a command the returns the current url and title as one result (just to show an example) - client.addCommand("getUrlAndTitle", function(callback) { - this.url( - function(urlResult) - { - this.getTitle( - function(titleResult) +// create a command the returns the current url and title as one result (just to show an example) +client.addCommand("getUrlAndTitle", function(callback) { + this.url( + function(urlResult) + { + this.getTitle( + function(titleResult) + { + var specialResult = {url: urlResult.value, title: titleResult}; + if (typeof callback == "function") { - var specialResult = {url: urlResult.value, title: titleResult}; - if (typeof callback == "function") - { - callback(specialResult); - } + callback(specialResult); } - ) - } - ); - }); - - client - .init() - .url("http://www.google.com") - .getUrlAndTitle(function(result) - { - console.log(result); - }) - .end(); + } + ) + } + ); +}); + +client + .init() + .url("http://www.google.com") + .getUrlAndTitle(function(result) + { + console.log(result); + }) + .end(); +``` ### Example of using webdriverjs for testing locally Run selenium server first: - java -jar selenium-server-standalone-2.5.0.jar +```shell +java -jar selenium-server-standalone-2.5.0.jar +``` -Then run this with nodjs: - - var webdriverjs = require("webdriverjs"); - var client = webdriverjs.remote(); +Then run this with nodejs: - client - .testMode() - .init() - .url("https://github.com") - .tests.cssPropertyEquals(".login a", "color", "#4183c4", "Color of .login a is #4183c4") - .tests.titleEquals("Secure source code hosting and collaborative development - GitHub", "Title of the page is 'Secure source code hosting and collaborative development - GitHub'") - .click(".pricing a") - .tests.titleEquals("Plans & Pricing - GitHub", "Title of the page is 'Plans & Pricing - GitHub'") - .tests.visible(".pagehead", true, ".pagehead is visible after click") - .end(); +```js +var webdriverjs = require("webdriverjs"); +var client = webdriverjs.remote(); + +client + .testMode() + .init() + .url("https://github.com") + .tests.cssPropertyEquals(".login a", "color", "#4183c4", "Color of .login a is #4183c4") + .tests.titleEquals("Secure source code hosting and collaborative development - GitHub", "Title of the page is 'Secure source code hosting and collaborative development - GitHub'") + .click(".pricing a") + .tests.titleEquals("Plans & Pricing - GitHub", "Title of the page is 'Plans & Pricing - GitHub'") + .tests.visible(".pagehead", true, ".pagehead is visible after click") + .end(); +``` # List of current helper methods These are the current implemented helper methods. All methods take from 0 to a couple of parameters. Also all methods accept a callback so that we can assert values or have more logic when the callback is called. @@ -233,28 +247,4 @@ The npm module for this library is maintained by: * [Camilo Tapia](http://github.com/Camme) * [Dan Jenkins](http://github.com/danjenkins) - -## License - -(The MIT License) - -Copyright (c) 2011 Camilo Tapia <camilo.tapia@gmail.com> - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* [Christian Bromann](https://github.com/christian-bromann) \ No newline at end of file