diff --git a/.travis.yml b/.travis.yml index fbe9328f..2496d8b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - 0.8 - - 0.10.1 + - 0.10.33 before_install: - npm conf set strict-ssl false diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c34c988..076b3f41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,97 @@ # Change Log +# 0.6.16 + * Fixing usage of cookie-parser and body-parser [PR](https://github.com/yahoo/arrow/pull/291) + +# 0.6.15 + * Adding cookie-parser and body-parser dependencies [PR](https://github.com/yahoo/arrow/pull/290) + +# 0.6.14 + * Updating shrinkwrap for Express update [PR](https://github.com/yahoo/arrow/pull/289) + +# 0.6.13 + + * Updating Express to 4.x [PR](https://github.com/yahoo/arrow/pull/287) + +# 0.6.12 + + * Adding support for passing sauce tunnel in capabilities [PR](https://github.com/yahoo/arrow/pull/285) + +# 0.6.11 + + * Adding support for passing sauce username and accesskey in capabilities [PR](https://github.com/yahoo/arrow/pull/284) + +# 0.6.10 + + * Update sauce labs dashboard with test results [PR](https://github.com/yahoo/arrow/pull/282) + +# 0.6.9 + + * Adding support to show sauce labs report url in report [PR](https://github.com/yahoo/arrow/pull/278) + +# 0.6.8 + + * Updating capabilities for iOS [PR](https://github.com/yahoo/arrow/pull/275) + +# 0.6.7 + + * Add the capacity to record POST body and access it from proxy manager's record [PR](https://github.com/yahoo/arrow/pull/271) + +# 0.6.6 + + * Fix for screenshots getting overwritten if there are multiple test failures in one descriptor [PR](https://github.com/yahoo/arrow/pull/270) [Issue](https://github.com/yahoo/arrow/issues/269) + +# 0.6.5 + + * Fix for supporting context with datadriven descriptors and fixing shrinkwrap [PR](https://github.com/yahoo/arrow/pull/267) + +# 0.6.4 + + * Setting rejectUnauthorized to false for webservice controller [PR](https://github.com/yahoo/arrow/pull/266) + * Setting express version to 3.x and Mocha to ~1.18.2 [PR](https://github.com/yahoo/arrow/pull/252) + +# 0.6.3 + + * Fix to avoid ECONNRESET issue with Nodejs 10 [PR](https://github.com/yahoo/arrow/pull/250) + +# 0.6.2 + + * Restarting phantomjs before retry, if it crashed while test execution [PR](https://github.com/yahoo/arrow/pull/243) [Issue](https://github.com/yahoo/arrow/issues/240) + * Add additional checks for markup-test.js [PR](https://github.com/yahoo/arrow/pull/244) + +# 0.6.1 + + * Fix for exitCode not working for unit tests [PR](https://github.com/yahoo/arrow/pull/239) + * Fixing condition for descriptorSharedParams [PR](https://github.com/yahoo/arrow/pull/238) + +# 0.6.0 + + * Adding support for data driven descriptors [PR](https://github.com/yahoo/arrow/pull/237) [Documentation](http://yahoo.github.io/arrow/arrow_FAQs.html#how-can-I-reuse-same-descriptor-with-different-sets-of-data) + * Adding support for sharing parameters from descriptors [PR](https://github.com/yahoo/arrow/pull/237) [Documentation](http://yahoo.github.io/arrow/arrow_FAQs.html#how-can-I-share-params-from-my-descriptor) + * Error handling for JSON parsing in webservice controller [PR](https://github.com/yahoo/arrow/pull/235) + +# 0.5.3 + + * Adding support for specifying comments in descriptor [PR](https://github.com/yahoo/arrow/pull/232) + * Making nodejs tests honor logLevel [PR](https://github.com/yahoo/arrow/pull/232) + * Fixed the issue - space after a comma in the 'commonLib' string in 'test-descriptor.json' causes a fail [Issue](https://github.com/yahoo/arrow/issues/206) [PR](https://github.com/yahoo/arrow/pull/233) + +# 0.5.2 + + * Using cdnjs link for yui [PR](https://github.com/yahoo/arrow/pull/228) + * Adding support to pass capabilities as JSON object, merging default capabilities with user defined capabilities [PR](https://github.com/yahoo/arrow/pull/227) + +# 0.5.1 + + * Adding support for Android browser [PR](https://github.com/yahoo/arrow/pull/219) + * Adding support to resize the browser window [PR](https://github.com/yahoo/arrow/pull/205) + * Fixing the issue - Error: EMFILE, too many open files 'node/proxy.log [Issue](https://github.com/yahoo/arrow/issues/217) [PR](https://github.com/yahoo/arrow/pull/218) + +# 0.5.0 + + * Adding feature to Import tests from other descriptors based test or group [ Details - https://github.com/yahoo/arrow/pull/200 ] + * Adding support for webdriver key object and improved error messaging [ Details - https://github.com/yahoo/arrow/pull/201 ] + # 0.4.3 * adding path method to return installed arrow directory [ Details - https://github.com/yahoo/arrow/pull/199 ] diff --git a/README.md b/README.md index f6e6dfe1..8f6b5024 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ + +***NOTE: This project is under maintenance mode and is not actively worked upon. We will only work on severe issues/bugs,if and when needed. Please feel free to fork it if you want to add a feature or make any enhancement. + #Arrow [![Build Status](https://secure.travis-ci.org/yahoo/arrow.png?branch=master)](http://travis-ci.org/yahoo/arrow)[![NPM version](https://badge.fury.io/js/yahoo-arrow.png)](http://badge.fury.io/js/yahoo-arrow) @@ -38,10 +41,12 @@ npm install -g yahoo-arrow * **--seleniumHost** : (optional) override selenium host url (example: --seleniumHost=http://host.com:port/wd/hub) * **--capabilities** : (optional) the name of a json file containing webdriver capabilities required by your project * **--startProxyServer** : (optional) true/false. Starts a proxy server, intercepting all selenium browser calls -* **--routerProxyConfig** : (optional) filePath. Expects a Json file, allows users to modify host and headers for all calls being made by browser. Also supports recording of select url calls ( if you mark "record" : true) +* **--routerProxyConfig** : (optional) filePath. Expects a Json file, allows users to modify host and headers for all calls being made by browser. Also supports recording of select url calls ( if you mark "record" : true), and also supports recording the body of POST request (if you mark "storeBody": true), the default limit size of post body is 10240 bytes, you can change it by assigning "sizeLimit" : {integer in byte}. Example Json : { + "storeBody" : true, + "sizeLimit": 4096, "router":{ "yahoo.com": { "newHost": "x.x.x.x (your new host ip/name)", diff --git a/arrow_server/server.js b/arrow_server/server.js index 42a437ac..cce5f477 100755 --- a/arrow_server/server.js +++ b/arrow_server/server.js @@ -16,6 +16,8 @@ var path = require("path"); var nopt = require("nopt"); var http = require("http"); var express = require("express"); +var bodyParser = require("body-parser"); +var cookieParser = require("cookie-parser"); var log4js = require("log4js"); var portchecker = require('../ext-lib/portchecker'); @@ -77,8 +79,8 @@ if (parsed["debug"]) { var app = express(); app.use(log4js.connectLogger(logger)); -app.use(express.cookieParser()); -app.use(express.bodyParser()); +app.use(cookieParser()); +app.use(bodyParser.json()); var mimes = { "css":"text/css", @@ -360,7 +362,7 @@ app.get("/wd/hub/session/:sessionId", function (req, res) { }); // Delete the session -app.del("/wd/hub/session/:sessionId", function (req, res) { +app.delete("/wd/hub/session/:sessionId", function (req, res) { res.contentType("application/json"); res.send({status:9, value:"Delete session: Not Implemented"}, 501); }); diff --git a/config/config.js b/config/config.js index 6a0a50f3..c6388597 100644 --- a/config/config.js +++ b/config/config.js @@ -9,6 +9,9 @@ var config = {}; // User default config config.seleniumHost = ""; config.phantomHost = "http://localhost:4445/wd/hub"; +config.sauceLabsHost = "http://ondemand.saucelabs.com:80/wd/hub"; +config.sauceUsername = ""; +config.sauceAccesskey = ""; config.context = ""; config.defaultAppHost = ""; config.logLevel = "INFO"; @@ -20,7 +23,7 @@ config.baseUrl = ""; config.arrowModuleRoot = global.appRoot + "/"; config.dimensions = config.arrowModuleRoot + "config/dimensions.json"; config.defaultTestHost = config.arrowModuleRoot + "lib/client/testHost.html"; -config.defaultAppSeed = "http://yui.yahooapis.com/3.8.0/build/yui/yui-min.js"; +config.defaultAppSeed = "//cdnjs.cloudflare.com/ajax/libs/yui/3.15.0/yui-min.js"; config.autolib = config.arrowModuleRoot + "lib/common"; //for yui sandbox diff --git a/config/descriptor-schema.json b/config/descriptor-schema.json index 20093639..6f9bb0f4 100644 --- a/config/descriptor-schema.json +++ b/config/descriptor-schema.json @@ -8,10 +8,13 @@ "extends" : { "type" : "string"}, "startProxyServer" : { "type" : "boolean"}, "routerProxyConfig" : { "type" : "string"}, + "comment" : { "type" : "string"}, "config" : { "type" : "object" }, + "dataDriver":{"type": "string"}, + "importDescriptor":{ "type":"array", "items":[ @@ -36,7 +39,9 @@ "required":true, "additionalProperties" : { "type" : "object", + "properties" : { + "comment" : { "type" : "string"}, "enabled" : { "type" : "boolean | string" }, "controller" : { "type" : "string" }, "group" : { "type" : "string" }, diff --git a/demo/mocha/importTests/finance-descriptor.json b/demo/mocha/importTests/finance-descriptor.json index 46754bf2..dfab156e 100644 --- a/demo/mocha/importTests/finance-descriptor.json +++ b/demo/mocha/importTests/finance-descriptor.json @@ -28,10 +28,35 @@ "test": "../test/test-quote-mocha.js", "quote": "Yahoo! Inc. (YHOO)" + } + ] + } + }, + + "Test AAPL Ticker" : { + "group" : "smoke", + "params" :{ + + "scenario": [ + { + "page": "$$config.baseUrl$$" + }, + { + "controller": "locator", + "params": { + "value": "#txtQuotes", + "text": "aapl\n" + } + }, + { + "test": "../test/test-quote-mocha.js", + "quote": "Apple Inc. (AAPL)" + } ] } } + } }, { diff --git a/demo/mocha/test/finance-controller-mocha.js b/demo/mocha/test/finance-controller-mocha.js index 0f208d42..68daaa50 100644 --- a/demo/mocha/test/finance-controller-mocha.js +++ b/demo/mocha/test/finance-controller-mocha.js @@ -54,7 +54,7 @@ FinanceCustomController.prototype.execute = function(callback) { webdriver.waitForElementPresent(webdriver.By.css(".title")).then(function() { self.driver.executeTest(self.testConfig, self.testParams, function(error, report) { - callback(); + callback(error); }); }); diff --git a/demo/mocha/test/import-descriptor-all.json b/demo/mocha/test/import-descriptor-all.json new file mode 100644 index 00000000..8069a76a --- /dev/null +++ b/demo/mocha/test/import-descriptor-all.json @@ -0,0 +1,35 @@ +[ + { + "settings": [ "master" ], + + "name" : "import_test", + + "config": { + "baseUrl": "http://finance.yahoo.com" + }, + + "importDescriptor":[ + { + "path" : "../importTests/finance-descriptor.json" + } + + ], + + "dataprovider" : { + + "dummy_test" : { + "params" : { + "engine" : "mocha", + "engineConfig" : "./mocha-config.json", + "test" : "test-dummy-mocha.js", + "page" : "http://finance.yahoo.com" + }, + "group" : "int" + + } + + } + + + } +] diff --git a/demo/mocha/test/import-descriptor-group.json b/demo/mocha/test/import-descriptor-group.json index 720eb573..aa684f7c 100644 --- a/demo/mocha/test/import-descriptor-group.json +++ b/demo/mocha/test/import-descriptor-group.json @@ -11,7 +11,7 @@ "importDescriptor":[ { "path" : "../importTests/finance-descriptor.json", - "group":"func" + "group":["func"] } ] diff --git a/demo/mocha/test/import-descriptor-test.json b/demo/mocha/test/import-descriptor-test.json index 9827e8ed..aba4834a 100644 --- a/demo/mocha/test/import-descriptor-test.json +++ b/demo/mocha/test/import-descriptor-test.json @@ -11,9 +11,26 @@ "importDescriptor":[ { "path" : "../importTests/finance-descriptor.json", - "importTest":["Test YHOO Ticker"] + "test":["Test YHOO Ticker"] } - ] + ], + + "dataprovider" : { + + "dummy_test" : { + "params" : { + "engine" : "mocha", + "engineConfig" : "./mocha-config.json", + "test" : "test-dummy-mocha.js", + "page" : "http://finance.yahoo.com" + }, + "group" : "int" + + } + + } + + } ] diff --git a/demo/mocha/test/proxy-controller-record-mocha.js b/demo/mocha/test/proxy-controller-record-mocha.js index 3f9ec010..58662277 100644 --- a/demo/mocha/test/proxy-controller-record-mocha.js +++ b/demo/mocha/test/proxy-controller-record-mocha.js @@ -34,7 +34,7 @@ ProxyCustomController.prototype.execute = function (callback) { console.log(record); self.testParams.proxyManagerRecord = record; self.driver.executeTest(self.testConfig, self.testParams, function (error, report) { - callback(); + callback(error); }); }); diff --git a/demo/mocha/test/test-dummy-mocha.js b/demo/mocha/test/test-dummy-mocha.js new file mode 100644 index 00000000..06ca1062 --- /dev/null +++ b/demo/mocha/test/test-dummy-mocha.js @@ -0,0 +1,32 @@ +var + Y, + chai; + +describe('test-dummy-mocha', function(){ + describe('test', function(){ + + before(function (done) { + + // Initialize chai and YUI + if(typeof window == "undefined" && typeof chai == "undefined"){ + chai = require('chai'); + } + else{ + chai = window.chai; + } + + Y = YUI().use('node', function () + { + done(); + }); + + }); + + it('has dummy one', function(done){ + + chai.assert(1==1); + done(); + + }); + }); +}); \ No newline at end of file diff --git a/demo/test/capabilities.json b/demo/test/capabilities.json new file mode 100644 index 00000000..3806e65d --- /dev/null +++ b/demo/test/capabilities.json @@ -0,0 +1,11 @@ +{ + "capabilities": { + "mac_chrome": { + "browserName": "chrome", + "platform": "MAC" + } + }, + "common_capabilities": { + "javascriptEnabled": "true" + } +} \ No newline at end of file diff --git a/demo/test/datadriven/configdata.json b/demo/test/datadriven/configdata.json new file mode 100644 index 00000000..f9469580 --- /dev/null +++ b/demo/test/datadriven/configdata.json @@ -0,0 +1,16 @@ +{ + "config": [ + { + "finance": { + "baseUrl": "http://finance.yahoo.com", + "searchBtnId": "#mnp-search_box" + } + }, + { + "yahoo": { + "baseUrl": "http://yahoo.com", + "searchBtnId": "#p_13838465-p" + } + } + ] +} \ No newline at end of file diff --git a/demo/test/datadriven/dataDriventest.js b/demo/test/datadriven/dataDriventest.js new file mode 100644 index 00000000..0c466fc0 --- /dev/null +++ b/demo/test/datadriven/dataDriventest.js @@ -0,0 +1,15 @@ +YUI.add("datadriven-tests", function(Y) { + 'use strict'; + var suite = new Y.Test.Suite("Data driven test"); + + suite.add(new Y.Test.Case({ + + "test search button": function() { + var node = Y.one(this.testParams.searchBtnId); + Y.Assert.isNotNull(node, "Search button not found"); + + } + })); + + Y.Test.Runner.add(suite); +}, "0.1", {requires:["node","test"]}); diff --git a/demo/test/datadriven/datadriven-context-descriptor.json b/demo/test/datadriven/datadriven-context-descriptor.json new file mode 100644 index 00000000..c5bfbbad --- /dev/null +++ b/demo/test/datadriven/datadriven-context-descriptor.json @@ -0,0 +1,52 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "config": [ + { + "finance": { + "baseUrl": "http://finance.yahoo.com" + } + }, + { + "yahoo": { + "baseUrl": "http://yahoo.com" + } + } + ], + + "dataprovider" : { + + "Test Data Driven Descriptor" : { + "group" : "func", + + "params" :{ + + "page": "$$config.baseUrl$$", + "test": "./test.js" + + } + + } + } + }, + { + "settings": [ "environment:development" ], + "config": [ + { + "finance": { + "baseUrl": "http://uk.finance.yahoo.com" + } + }, + { + "yahoo": { + "baseUrl": "http://uk.yahoo.com" + } + } + ] + + } + +] \ No newline at end of file diff --git a/demo/test/datadriven/datadriven-descriptor-config.json b/demo/test/datadriven/datadriven-descriptor-config.json new file mode 100644 index 00000000..1930120a --- /dev/null +++ b/demo/test/datadriven/datadriven-descriptor-config.json @@ -0,0 +1,43 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "config": [ + { + "finance": { + "baseUrl": "http://finance.yahoo.com", + "searchBtnId": "#mnp-search_box" + } + }, + { + "yahoo": { + "baseUrl": "http://yahoo.com", + "searchBtnId": "#p_13838465-p" + } + } + ], + + "dataprovider" : { + + "Test Data Driven Descriptor" : { + "group" : "func", + + "params" :{ + + "page": "$$config.baseUrl$$", + "test": "dataDriventest.js", + "searchBtnId":"$$config.searchBtnId$$" + + } + + } + } + }, + { + "settings": [ "environment:development" ] + } + +] + diff --git a/demo/test/datadriven/datadriven-descriptor.json b/demo/test/datadriven/datadriven-descriptor.json new file mode 100644 index 00000000..e5396694 --- /dev/null +++ b/demo/test/datadriven/datadriven-descriptor.json @@ -0,0 +1,30 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "dataDriver" : "./configdata.json", + + "dataprovider" : { + + "Test Data Driven Descriptor" : { + "group" : "func", + + "params" :{ + + "page": "$$config.baseUrl$$", + "test": "dataDriventest.js", + "searchBtnId":"$$config.searchBtnId$$" + + } + + } + } + }, + { + "settings": [ "environment:development" ] + } + +] + diff --git a/demo/test/datadriven/test.js b/demo/test/datadriven/test.js new file mode 100644 index 00000000..64ae7e27 --- /dev/null +++ b/demo/test/datadriven/test.js @@ -0,0 +1,11 @@ +YUI.add("assrt-tests", function(Y) { + var suite = new Y.Test.Suite("Assert Page test of the test"); + suite.add(new Y.Test.Case({ + "test assert": function() { + + Y.Assert.areEqual("1", "1"); + } + })); + + Y.Test.Runner.add(suite); +}, "0.1", {requires:["node","test"]}); diff --git a/demo/test/finance-controller-descriptor.json b/demo/test/finance-controller-descriptor.json index cf5123b5..be8e3913 100644 --- a/demo/test/finance-controller-descriptor.json +++ b/demo/test/finance-controller-descriptor.json @@ -7,12 +7,15 @@ "config":{ "baseUrl":"http://finance.yahoo.com" }, + "comment":"Tests for finance", "dataprovider":{ "Test YHOO Ticker using Finance Controller":{ + "comment":"This is a finance test for Yahoo ticker", "group":"func", "controller":"finance-controller.js", + "params":{ "page":"$$config.baseUrl$$", "txtLocator":"#txtQuotes", diff --git a/demo/test/finance-scenario-descriptor.json b/demo/test/finance-scenario-descriptor.json index cc28156b..cf09318f 100644 --- a/demo/test/finance-scenario-descriptor.json +++ b/demo/test/finance-scenario-descriptor.json @@ -7,19 +7,21 @@ "config": { "baseUrl": "http://finance.yahoo.com" }, - + "comment":"Tests for finance", "dataprovider" : { "Test YHOO Ticker" : { "group" : "func", - + "comment":"Ticker test", "params" :{ "scenario": [ { + "comment":"Load finance page", "page": "$$config.baseUrl$$" }, { + "comment":"Type yhoo in #txtquotes", "controller": "locator", "params": { "value": "#txtQuotes", @@ -27,6 +29,7 @@ } }, { + "comment":"Verify if the quote symbol matches", "test": "test-quote.js", "quote": "Yahoo! Inc. (YHOO)" } diff --git a/demo/test/import-multiple-descriptor.json b/demo/test/import-multiple-descriptor.json new file mode 100644 index 00000000..19e097b6 --- /dev/null +++ b/demo/test/import-multiple-descriptor.json @@ -0,0 +1,40 @@ +[ + { + "settings": [ "master" ], + + "name" : "tabview", + + "config" :{ + "baseUrl" : "http://finance.yahoo.com" + }, + + "importDescriptor":[ + { + "path" : "./importTests/finance-descriptor.json", + "group" : ["func"] + }, + { + "path" : "./importTests/finance-descriptor2.json", + "group" : ["func"] + } + ], + + "dataprovider" : { + + "dom_int" : { + "params" : { + "test" : "test-assert-3.js", + "page" : "$$config.baseUrl$$" + }, + "group" : "smoke" + } + + } + + }, + + { + "settings": [ "environment:development" ] + } + +] \ No newline at end of file diff --git a/demo/test/importTests/finance-descriptor.json b/demo/test/importTests/finance-descriptor.json new file mode 100644 index 00000000..13fb97b8 --- /dev/null +++ b/demo/test/importTests/finance-descriptor.json @@ -0,0 +1,65 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "config": { + "baseUrl": "http://finance.yahoo.com" + }, + + "dataprovider" : { + "Test YHOO Ticker" : { + "group" : "func", + "params" :{ + + "scenario": [ + { + "page": "$$config.baseUrl$$" + }, + { + "controller": "locator", + "params": { + "value": "#txtQuotes", + "text": "yhoo\n" + } + }, + { + "test": "../test-quote.js", + "quote": "Yahoo! Inc. (YHOO)" + } + ] + } + }, + + "Test AAPL Ticker" : { + "group" : "smoke", + "params" :{ + + "scenario": [ + { + "page": "$$config.baseUrl$$" + }, + { + "controller": "locator", + "params": { + "value": "#txtQuotes", + "text": "yhoo\n" + } + }, + { + "test": "../test-quote.js", + "quote": "Yahoo! Inc. (YHOO)" + } + ] + } + } + + } + }, + { + "settings": [ "environment:development" ] + } + +] + diff --git a/demo/test/importTests/finance-descriptor2.json b/demo/test/importTests/finance-descriptor2.json new file mode 100644 index 00000000..8363a395 --- /dev/null +++ b/demo/test/importTests/finance-descriptor2.json @@ -0,0 +1,40 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "config": { + "baseUrl": "http://finance.yahoo.com" + }, + + "dataprovider" : { + "Test Aseert" : { + "group" : "smoke", + "params" :{ + "test" : "../test-assert-3.js", + "page" : "$$config.baseUrl$$" + } + }, + + "Test Window Size" : { + "group" : "func", + "browser":"firefox", + "params" :{ + "page": "$$config.baseUrl$$", + "test": "../test-browser-size.js", + "lib": "../test-lib.js", + "windowSize": { + "width": "512", + "height": 512 + } + } + } + + } + }, + { + "settings": [ "environment:development" ] + } + +] \ No newline at end of file diff --git a/demo/test/proxy-controller-postbody.js b/demo/test/proxy-controller-postbody.js new file mode 100644 index 00000000..54670fa1 --- /dev/null +++ b/demo/test/proxy-controller-postbody.js @@ -0,0 +1,49 @@ +/*jslint forin:true sub:true anon:true, sloppy:true, stupid:true nomen:true, node:true continue:true*/ + +/* + * Copyright (c) 2012, Yahoo! Inc. All rights reserved. + * Copyrights licensed under the New BSD License. + * See the accompanying LICENSE file for terms. + */ + +var util = require("util"); +var log4js = require("yahoo-arrow").log4js; +var Controller = require("yahoo-arrow").controller; + +function ProxyCustomController(testConfig, args, driver) { + Controller.call(this, testConfig, args, driver); + + this.logger = log4js.getLogger("ProxyCustomController"); +} +util.inherits(ProxyCustomController, Controller); + +ProxyCustomController.prototype.execute = function (callback) { + + var self = this, + page, + webdriver; + + if (this.driver.webdriver) { + + page = this.testParams.page; + webdriver = this.driver.webdriver; + + webdriver.get(page); + + webdriver.waitForElementPresent(webdriver.By.css("#yucsHead")).then(function () { + + var record = JSON.parse(self.getProxyRecord()); + + self.testParams.networkTrafficRecord = record; + self.driver.executeTest(self.testConfig, self.testParams, function (error, report) { + callback(); + }); + + }); + } else { + this.logger.fatal("Custom Controllers are currently only supported on Selenium Browsers"); + callback("Custom Controllers are currently only supported on Selenium Browsers"); + } +} + +module.exports = ProxyCustomController; diff --git a/demo/test/proxy-postbody-descriptor.json b/demo/test/proxy-postbody-descriptor.json new file mode 100644 index 00000000..9f01b7ce --- /dev/null +++ b/demo/test/proxy-postbody-descriptor.json @@ -0,0 +1,32 @@ +[ + { + "settings":[ "master" ], + + "name":"controllers", + + "startProxyServer" : true, + + "routerProxyConfig" : "./router-postbody.json", + + "config":{ + "baseUrl":"http://news.yahoo.com" + }, + + "dataprovider":{ + + "Test proxy Controller":{ + "group":"func", + "controller":"./proxy-controller-postbody.js", + "params":{ + "page":"$$config.baseUrl$$", + + "test":"./test-proxy-postbody.js" + + } + } + } + }, + { + "settings":[ "environment:development" ] + } +] diff --git a/demo/test/router-postbody.json b/demo/test/router-postbody.json new file mode 100644 index 00000000..d1466e35 --- /dev/null +++ b/demo/test/router-postbody.json @@ -0,0 +1,8 @@ +{ + "storeBody" : true, + "sizeLimit": 4096, + "geo.query.yahoo.com": { + "method": "POST", + "record": true + } +} diff --git a/demo/test/shared-params/shared-params-controller-descriptor.json b/demo/test/shared-params/shared-params-controller-descriptor.json new file mode 100644 index 00000000..ed5819a0 --- /dev/null +++ b/demo/test/shared-params/shared-params-controller-descriptor.json @@ -0,0 +1,71 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "config": { + "descriptorSharedParams" :{ + "yhooquote": "Yahoo! Inc. (YHOO)", + "applequote": "Apple Inc. (AAPL)" + } + }, + + + "dataprovider" : { + + "Test YHOO Ticker" : { + "group" : "func", + + "params" :{ + + "scenario": [ + { + "page": "http://finance.yahoo.com" + }, + { + "controller": "locator", + "params": { + "value": "#txtQuotes", + "text": "yhoo\n" + } + }, + { + "test": "test-quote-yhoo-shared-params.js" + } + ] + } + + }, + + "Test AAPL Ticker" : { + "group" : "func", + + "params" :{ + + "scenario": [ + { + "page": "http://finance.yahoo.com" + }, + { + "controller": "locator", + "params": { + "value": "#txtQuotes", + "text": "aapl\n" + } + }, + { + "test": "test-quote-aapl-shared-params.js" + } + ] + } + + } + } + }, + { + "settings": [ "environment:development" ] + } + +] + diff --git a/demo/test/shared-params/shared-params-scenario-descriptor.json b/demo/test/shared-params/shared-params-scenario-descriptor.json new file mode 100644 index 00000000..820a9ce3 --- /dev/null +++ b/demo/test/shared-params/shared-params-scenario-descriptor.json @@ -0,0 +1,62 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "config": { + + "descriptorSharedParams" :{ + "yhooquote": "Yahoo! Inc. (YHOO)", + "applequote": "Apple Inc. (AAPL)" + } + }, + + "dataprovider" : { + + "Test YHOO Ticker" : { + "group" : "func", + + "params" :{ + + "scenario": [ + { + "page": "http://finance.yahoo.com" + }, + { + "controller": "locator", + "params": { + "value": "#txtQuotes", + "text": "yhoo\n" + } + }, + { + "test": "test-quote-yhoo-shared-params.js" + }, + + { + "page": "http://finance.yahoo.com" + }, + { + "controller": "locator", + "params": { + "value": "#txtQuotes", + "text": "aapl\n" + } + }, + { + "test": "test-quote-aapl-shared-params.js" + } + + ] + } + + } + } + }, + { + "settings": [ "environment:development" ] + } + +] + diff --git a/demo/test/shared-params/test-quote-aapl-shared-params.js b/demo/test/shared-params/test-quote-aapl-shared-params.js new file mode 100644 index 00000000..96c670f4 --- /dev/null +++ b/demo/test/shared-params/test-quote-aapl-shared-params.js @@ -0,0 +1,13 @@ +YUI.add("appl-quote-tests", function(Y) { + var suite = new Y.Test.Suite("Quote Page AAPL test"); + suite.add(new Y.Test.Case({ + "test aapl quote": function() { + + var quote = this.testParams.descriptorSharedParams["applequote"]; + Y.Assert.areEqual(quote, Y.one(".yfi_rt_quote_summary").one("h2").get('text')); + + } + })); + + Y.Test.Runner.add(suite); +}, "0.1", {requires:["node","test"]}); diff --git a/demo/test/shared-params/test-quote-yhoo-shared-params.js b/demo/test/shared-params/test-quote-yhoo-shared-params.js new file mode 100644 index 00000000..e4221f30 --- /dev/null +++ b/demo/test/shared-params/test-quote-yhoo-shared-params.js @@ -0,0 +1,13 @@ +YUI.add("yhoo-quote-tests", function(Y) { + var suite = new Y.Test.Suite("Quote Page YHOO test"); + suite.add(new Y.Test.Case({ + "test yhoo quote": function() { + + var quote = this.testParams.descriptorSharedParams["yhooquote"]; + Y.Assert.areEqual(quote, Y.one(".yfi_rt_quote_summary").one("h2").get('text')); + + } + })); + + Y.Test.Runner.add(suite); +}, "0.1", {requires:["node","test"]}); diff --git a/demo/test/test-assert-3.js b/demo/test/test-assert-3.js new file mode 100644 index 00000000..c6316501 --- /dev/null +++ b/demo/test/test-assert-3.js @@ -0,0 +1,34 @@ +YUI.add("MyAwesomeModule-tests", function (Y) { + 'use strict'; + + var suite = new Y.Test.Suite("Assertion Tests 3"); + + suite.add(new Y.Test.Module({ + + "name" : "Assertion Test 3", + "id": "ms-market-strip-0", + + "asserts" : { + "Logo Present" : { + "locator" : ".Carousel-Item", + "type" : "isNode" + }, + "Test Greater than" : { + "locator" : ".Carousel-Item", + "type" : "nodeCount", + "expected" : ">1", + "message" : "There should be more than 1 list items with class yuhead-com-link-item" + }, + "Test Less than" : { + "locator" : ".Carousel-Item", + "type" : "nodeCount", + "expected" : "<100", + "message" : "There should be more than 5 list items with class yuhead-com-link-item" + } + + } + })); + + Y.Test.Runner.add(suite); + +}, "0.1", {requires : ["test", "node", "html-module-lib", "dom-lib"]}); \ No newline at end of file diff --git a/demo/test/test-browser-size.js b/demo/test/test-browser-size.js new file mode 100644 index 00000000..5c09dae9 --- /dev/null +++ b/demo/test/test-browser-size.js @@ -0,0 +1,16 @@ +YUI().use('test', function (Y) { + + var suite = new Y.Test.Suite("Browser size test"); + suite.add(new Y.Test.Case({ + + "test browser size equals parameter": function() { + var expectedSize = this.testParams['windowSize']; + + Y.Assert.areEqual(parseInt(expectedSize.width, 10), window.outerWidth); + Y.Assert.areEqual(parseInt(expectedSize.height, 10), window.outerHeight); + } + + })); + + Y.Test.Runner.add(suite); +}); diff --git a/demo/test/test-proxy-postbody.js b/demo/test/test-proxy-postbody.js new file mode 100644 index 00000000..5b9af526 --- /dev/null +++ b/demo/test/test-proxy-postbody.js @@ -0,0 +1,33 @@ +/* + * Like other tests, this is a YUI test module + * + */ +YUI.add("test-proxy-postbody-tests", function (Y) { + + //We initialize the suite object as a YUI test suite and with a suite title + var suite = new Y.Test.Suite("Test for record:true"); + suite.add(new Y.Test.Case({ + + //testing headers host + "test the content of postbody": function () { + + var record = this.testParams.networkTrafficRecord, + i, hasPostBody = false; + + Y.Assert.isNotNull(record, "The value of network record is null"); + for (i = 0; i < record.length; i += 1) { + if (record[i].body && record[i].body.text) { + Y.Assert.isTrue(record[i].body.text.indexOf('q=select') === 0, "The content of POST body should start with 'q=select' ! " + record[i].body.text); + hasPostBody = true; + } + } + Y.Assert.isTrue(hasPostBody, "The POST BODY of all record should not be empty!"); + } + + + })); + + //Never "run" the tests, simply add them to the suite. Arrow takes care of running them + Y.Test.Runner.add(suite); +}, "0.1", {requires: ["test", "node"]}); + diff --git a/demo/test/test_window_size_descriptor.json b/demo/test/test_window_size_descriptor.json new file mode 100755 index 00000000..f4aad6f8 --- /dev/null +++ b/demo/test/test_window_size_descriptor.json @@ -0,0 +1,28 @@ +[ + { + "settings": [ "master" ], + "name" : "descriptor", + "config": { + "baseUrl": "http://login.yahoo.com" + }, + + "dataprovider" : { + + "Set browser size" : { + "group" : "func", + "browser":"firefox", + "params" :{ + "page": "$$config.baseUrl$$", + "test": "test-browser-size.js", + "windowSize": { + "width": "512", + "height": 512 + } + } + } + } + }, + { + "settings": [ "environment:development" ] + } +] diff --git a/docs/arrow_cookbook/arrow_in-depth.rst b/docs/arrow_cookbook/arrow_in-depth.rst index 83da1456..8f0048c4 100644 --- a/docs/arrow_cookbook/arrow_in-depth.rst +++ b/docs/arrow_cookbook/arrow_in-depth.rst @@ -1341,9 +1341,8 @@ Example - var record = JSON.parse(self.getProxyRecord()); // Get the proxy record self.testParams.proxyManagerRecord=record; - self.testParams.page=null; self.driver.executeTest(self.testConfig, self.testParams, function(error, report) { - callback(); + callback(error); }); }); diff --git a/docs/arrow_cookbook/arrow_intro.rst b/docs/arrow_cookbook/arrow_intro.rst index a6499b78..bdd45489 100644 --- a/docs/arrow_cookbook/arrow_intro.rst +++ b/docs/arrow_cookbook/arrow_intro.rst @@ -5,7 +5,7 @@ Arrow is a test framework designed to promote test-driven JavaScript development Arrow aims to completely remove the line between development's Unit tests, and QE's functional and integration tests, by providing a uniform way to create and execute both. -Arrow itself, is a thin, extensible layer that marriages JavaScript, NodeJS, PhantomJS and Selenium. Arrow allows you to write tests using YUI-Test and execute those tests using NodeJS, PhantomJS or Selenium. Additionally, Arrow provides a rich mechanism for building, organizing and executing tests and test scenarios. +Arrow itself, is a thin, extensible layer that marries JavaScript, NodeJS, PhantomJS and Selenium. Arrow allows you to write tests using YUI-Test and execute those tests using NodeJS, PhantomJS or Selenium. Additionally, Arrow provides a rich mechanism for building, organizing and executing tests and test scenarios. Why Use Arrow ------------- @@ -30,7 +30,7 @@ Core components: User-facing Components: -* Controllers: If drivers allow you to dictate *where* to execute your tests, controllers, or scenario atoms allow you to dictate *when* to execute your tests. Arrow's default controller or scenario atom opens the page and executes the test. This works well for a large number of tests.However, if you require more complex scenario or more granular control, you can **easily** create your **own** controllers and **control** how and when your tests are executed. +* Controllers: If drivers allow you to dictate *where* to execute your tests, controllers, or scenario atoms allow you to dictate *when* to execute your tests. Arrow's default controller or scenario atom opens the page and executes the test. This works well for a large number of tests. However, if you require more complex scenario or more granular control, you can **easily** create your **own** controllers and **control** how and when your tests are executed. * Libs: Libs, or dependencies, are a way to include any necessary dependencies needed by your test. These can be things such as libraries you've created, the source code against which you are testing etc. .. image:: DetailedArchitectureDiagram.jpg diff --git a/docs/arrow_cookbook/arrow_tutorial.rst b/docs/arrow_cookbook/arrow_tutorial.rst index f16cbabb..1e2c2b74 100644 --- a/docs/arrow_cookbook/arrow_tutorial.rst +++ b/docs/arrow_cookbook/arrow_tutorial.rst @@ -18,9 +18,9 @@ Unit Tests The demo includes a *unit_test* folder and includes two files: +---------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+ -| `unit_test/src/greeter.js `_ | Simple YUI module that takes two parameters as input, inverses their order, and returns them as output | +| ``unit_test/src/greeter.js`` | Simple YUI module that takes two parameters as input, inverses their order, and returns them as output | +---------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+ -| `unit_test/test/test-unit.js >`_ | Unit test to validate the function. | +| ``unit_test/test/test-unit.js`` | Unit test to validate the function. | +---------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+ In the world of JS, unit tests validate JS functions/classes which do not interact with the DOM. Functionality which interacts with the DOM is usually considered to be functional and should be tested as such. @@ -193,4 +193,4 @@ Similarly, you can run functional tests (test-func.js) against the HTTP endpoint Conclusion ========== -As you can see, Arrow allows you to execute all types of tests (unit, functional and integration) using the same methodology. Unlike other frameworks, it does not dictate to you how to execute different tests. As far as Arrow is concerned, tests are just tests. \ No newline at end of file +As you can see, Arrow allows you to execute all types of tests (unit, functional and integration) using the same methodology. Unlike other frameworks, it does not dictate to you how to execute different tests. As far as Arrow is concerned, tests are just tests. diff --git a/docs/arrow_dependency_graph.png b/docs/arrow_dependency_graph.png new file mode 100644 index 00000000..4c74cea5 Binary files /dev/null and b/docs/arrow_dependency_graph.png differ diff --git a/docs/arrow_tutorial/action_test/test/locator-action.js b/docs/arrow_tutorial/action_test/test/locator-action.js deleted file mode 100644 index e2e830a9..00000000 --- a/docs/arrow_tutorial/action_test/test/locator-action.js +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2012, Yahoo! Inc. All rights reserved. - * Copyrights licensed under the New BSD License. - * See the accompanying LICENSE file for terms. - */ - -YUI.add("navigate-action", function (Y) { - var buttonNode = null; - - console.log("action initialized"); - - Y.namespace("arrow").action = { - setUp: function (callback) { - var locators, - locator, - doc = Y.one(document.body), - node, - buttonTarget, - i; - - console.log("action setUp"); - - locators = this.testParams["locators"]; - if (!locators) { - locators = [this.testParams["locator"]]; - } - - // all locators except the last one enter texts - for (i = 0; i < (locators.length - 1); i += 1) { - locator = locators[i]; - node = doc.one(locator.target); - node.set("value", locator.text); - } - - // save the buttonNode to click later - buttonTarget = locators[locators.length - 1].target; - buttonNode = doc.one(buttonTarget); - if (!buttonNode) { - callback("Could not find button node to click: " + buttonTarget); - } else { - callback(); - } - }, - - execute: function() { - console.log("action executed"); - buttonNode.simulate("click"); - } - } - -}, "0.1", {requires: ["node", "node-event-simulate"]}); - diff --git a/docs/arrow_tutorial/action_test/test/simple-action.js b/docs/arrow_tutorial/action_test/test/simple-action.js deleted file mode 100644 index 396d10d2..00000000 --- a/docs/arrow_tutorial/action_test/test/simple-action.js +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2012, Yahoo! Inc. All rights reserved. - * Copyrights licensed under the New BSD License. - * See the accompanying LICENSE file for terms. - */ - -YUI.add("simple-action", function (Y) { - - console.log("action initialized"); - - Y.namespace("arrow").action = { - setUp: function (callback) { - console.log("action setUp"); - callback(); - }, - - execute: function() { - console.log("action executed"); - window.location.href = "http://www.yahoo.com"; - } - } - -}, "0.1", {requires: []}); - diff --git a/docs/arrow_tutorial/action_test/test/test-quote.js b/docs/arrow_tutorial/action_test/test/test-quote.js deleted file mode 100644 index 63369bae..00000000 --- a/docs/arrow_tutorial/action_test/test/test-quote.js +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2012, Yahoo! Inc. All rights reserved. - * Copyrights licensed under the New BSD License. - * See the accompanying LICENSE file for terms. - */ - - -YUI({ useBrowserConsole: true }).use("node", "test", function(Y) { - var suite = new Y.Test.Suite("Quote Page test of the test"); - suite.add(new Y.Test.Case({ - "test quote": function() { - Y.Assert.areEqual("Yahoo! Inc. (YHOO)", Y.one(".yfi_rt_quote_summary").one("h2").get('text')); - } - })); - - Y.Test.Runner.add(suite); -}); - diff --git a/docs/arrow_tutorial/action_test/test/test_descriptor.json b/docs/arrow_tutorial/action_test/test/test_descriptor.json deleted file mode 100755 index 735048e0..00000000 --- a/docs/arrow_tutorial/action_test/test/test_descriptor.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { - "settings": [ "master" ], - - "name": "controllers", - - "config": { - }, - - "dataprovider" : { - - "text_enter" : { - "group" : "func", - "params" :{ - "scenario": [ - { - "page": "http://finance.yahoo.com", - "action": "locator-action.js", - "locators": [ - { - "target": "#txtQuotes", - "text": "yhoo" - }, - { - "target": "#btnQuotes" - } - ] - }, - { - "test": "test-quote.js" - } - ] - } - } - } - }, - - { - "settings": [ "environment:development" ] - } - -] diff --git a/lib/client/yuitest-runner.js b/lib/client/yuitest-runner.js index 397223cd..9deee118 100644 --- a/lib/client/yuitest-runner.js +++ b/lib/client/yuitest-runner.js @@ -9,40 +9,6 @@ YUI({ useBrowserConsole: true }).use("get", function (Y) { - function loadAction() { - YUI({ useBrowserConsole: true }).use(ARROW.testBag, function (Y) { - var action = Y.arrow ? Y.arrow.action : null; - - if (!action) { - ARROW.actionReport = JSON.stringify({"error": "Could not find an action to execute"}); - return; - } - - try { - action.testParams = ARROW.testParams; - - action.setUp(function (error, data) { - var interval; - - ARROW.actionReport = JSON.stringify({"error": error, "data": data}); - if (error) { // we cannot execute the action - return; - } - // wait for the report to be collected before executing the action - // because actions are supposed to navigate away - interval = setInterval(function () { - if (ARROW.actionReported) { - clearInterval(interval); - action.execute(); - } - }, 100); - }); - } catch (ex) { - ARROW.actionReport = JSON.stringify({"error": "Exception: " + ex}); - } - }); - } - function completeTest(testRunner) { var YTest = YUITest; diff --git a/lib/client/yuitest-seed.js b/lib/client/yuitest-seed.js index b0efc6a3..02f25831 100644 --- a/lib/client/yuitest-seed.js +++ b/lib/client/yuitest-seed.js @@ -14,13 +14,10 @@ // ARROW.testLibs = []; // ARROW.scriptType = "test"; // ARROW.testScript = "test-file.js"; -// ARROW.actionScript = "action-file.js"; // ARROW.onSeeded = function() { /* add test, hand over to runner */} ARROW.testBag = ["test"]; ARROW.testReport = null; -ARROW.actionReport = null; -ARROW.actionReported = false; // try to catch unhandled errors if ((typeof window !== "undefined") && !window.onerror) { @@ -179,9 +176,6 @@ if ((typeof window !== "undefined") && !window.onerror) { if (("test" === ARROW.scriptType) && (-1 !== name.indexOf("-tests"))) { //console.log("Found test module: " + name); ARROW.testBag.push(name); - } else if (("action" === ARROW.scriptType) && (-1 !== name.indexOf("-action"))) { - //console.log("Found test action: " + name); - ARROW.testBag.push(name); } }; @@ -194,7 +188,6 @@ if ((typeof window !== "undefined") && !window.onerror) { YUI = require("yui").YUI; //console.log("Injecting share lib seed (YUI global config)"); - var fs = require('fs'); if (ARROW.shareLibServerSeed !== undefined) { try { require(ARROW.shareLibServerSeed); diff --git a/lib/common/tests/markup-test-mocha.js b/lib/common/tests/markup-test-mocha.js index 7d11acbf..a0fbb5a6 100644 --- a/lib/common/tests/markup-test-mocha.js +++ b/lib/common/tests/markup-test-mocha.js @@ -40,7 +40,6 @@ var self = this, testParams = self.testParams, - quote = testParams["quote"], Y, chai, warnOnly = testParams["warnOnly"] || false; diff --git a/lib/common/tests/markup-test.js b/lib/common/tests/markup-test.js index 01ea3b9b..3cb9fec0 100644 --- a/lib/common/tests/markup-test.js +++ b/lib/common/tests/markup-test.js @@ -151,6 +151,15 @@ YUI.add("markup-common-tests", function (Y) { error.push({level: 'error', text: 'Anchor tag with inline javascript. Tsk tsk.'}); } + if(Y.one('img[src="spacer.gif"]')) { + error.push({level: 'warn', text: 'spacer.gif used - is this used for layout?'}); + } +/* + if(Y.one('img[src*="&"]:not([src*="&"])') || + Y.one('a[href*="&"]:not([href*="&"])')) { + error.push({level: 'error', text: 'Unencoded &'}); + } +*/ if(Y.one('label:not([for])')) { error.push({level: 'warn', text: 'Labels should probably specify the for attribute instead of relying on siblings.'}); } @@ -219,6 +228,11 @@ YUI.add("markup-common-tests", function (Y) { error.push({level: 'error', text: 'Some pretty non-semantic / legacy tags being used here.'}); } + if(Y.one('script:not([type])') || + Y.one('style:not([type])')) { + error.push({level: 'warn', text: 'script or style tag without type defined.'}); + } + if(Y.one('br + br')) { error.push({level: 'error', text: 'Multiple br tags in a row. Is that necessary?'}); } diff --git a/lib/controller/default.js b/lib/controller/default.js index abcf2dc8..7bafb181 100644 --- a/lib/controller/default.js +++ b/lib/controller/default.js @@ -135,6 +135,13 @@ DefaultController.prototype.executeScenario = function (callback) { childParams.shared = {}; } + // pass testParams.descriptorSharedParams down to child + if (self.testParams.descriptorSharedParams) { + childParams.descriptorSharedParams = self.testParams.descriptorSharedParams; + } else { + childParams.descriptorSharedParams = {}; + } + // TODO: add to the controllers report success or failure arrow.runController(controllerName, self.testConfig, childParams, self.driver, function (error) { if (error) { @@ -157,7 +164,7 @@ DefaultController.prototype.executeScenario = function (callback) { }; /** - * Default controller that opens a page and tests. It also handles scenario + * Default controller that opens a page and tests. It also handles scenario * execution if given. * * @param callback function to call when done. It receives errorMsg as a parameter. @@ -166,11 +173,9 @@ DefaultController.prototype.execute = function (callback) { var self = this; if (self.testParams.scenario) { self.executeScenario(callback); - } else if (self.testParams.action) { - self.driver.executeAction(self.testConfig, self.testParams, callback); } else { if (!self.testParams.test && self.testParams.page) { - self.driver.navigate(self.testParams.page, callback); + self.driver.navigate(self.testParams, callback); } else if (self.testParams.test) { self.driver.executeTest(self.testConfig, self.testParams, callback); } else { diff --git a/lib/controller/locator.js b/lib/controller/locator.js index 3dd7b8ac..766b6c03 100644 --- a/lib/controller/locator.js +++ b/lib/controller/locator.js @@ -8,7 +8,6 @@ var util = require("util"); var log4js = require("log4js"); -var async = require("async"); var Controller = require("../interface/controller"); function LocatorController(testConfig, testParams, driver) { diff --git a/lib/controller/webservice-controller.js b/lib/controller/webservice-controller.js index c6c62973..a1665fe6 100644 --- a/lib/controller/webservice-controller.js +++ b/lib/controller/webservice-controller.js @@ -51,7 +51,8 @@ WebServiceController.prototype.execute = function(callback) { method: self.testParams.method || 'GET', headers: { // seems that user-agent is MUST to query YQL 'user-agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31" - } + }, + rejectUnauthorized: false } // http or https? @@ -89,11 +90,20 @@ WebServiceController.prototype.execute = function(callback) { callback(); }); } else if (content_type.indexOf('json') > -1) { // content type is json - var result = JSON.parse(data); - self.logger.debug("Response data:" + JSON.stringify(result)); - shared.data = result; - self.testParams.shared = shared; - callback(); + var result; + try { + result = JSON.parse(data); + self.logger.debug("Response data:" + JSON.stringify(result)); + shared.data = result; + self.testParams.shared = shared; + callback(); + } + catch(e) { + self.logger.error('Error while parsing the JSON data received from the call - ' + url); + self.logger.error('The data being parsed -' + data); + self.logger.error('\n\nError::' + e); + callback(e); + } } else { self.testParams.shared = shared; callback('Only json or xml content type is supported'); diff --git a/lib/driver/node.js b/lib/driver/node.js index 1e86b36a..94963edf 100644 --- a/lib/driver/node.js +++ b/lib/driver/node.js @@ -24,7 +24,6 @@ var path = require("path"); function NodeDriver(config, args) { Driver.call(this, config, args); coverage.configure(config); - this.logger = log4js.getLogger("NodeDriver"); } @@ -53,7 +52,8 @@ NodeDriver.prototype.createNodeArgs = function (testConfig, testParams, callback engineMgr, deplibs, i, - resolvePath; + resolvePath, + logLevel; resolvePath = function (prepath) { if (typeof prepath !== "string")return prepath; @@ -87,6 +87,9 @@ NodeDriver.prototype.createNodeArgs = function (testConfig, testParams, callback seed = engineMgr.getTestSeed(engine); runner = engineMgr.getTestRunner(engine); + // Pass logLevel to child process + logLevel = self.config['logLevel'] || 'info'; + logger.debug("engine config is:" + JSON.stringify(engineConfig)); logger.debug("seed is:" + seed); logger.debug("runner is " + runner); @@ -96,7 +99,7 @@ NodeDriver.prototype.createNodeArgs = function (testConfig, testParams, callback deplibs = libs.split(","); if (deplibs && deplibs.length > 0) { for (i = 0; i < deplibs.length; i++) { - deplibs[i] = resolvePath(deplibs[i]); + deplibs[i] = resolvePath(deplibs[i].trim()); } } libs = deplibs.join(); @@ -114,7 +117,8 @@ NodeDriver.prototype.createNodeArgs = function (testConfig, testParams, callback "libs": libs, "coverage": self.config.coverage, "coverageExclude": self.config.coverageExclude, - "testTimeOut": self.config.testTimeOut + "testTimeOut": self.config.testTimeOut, + "logLevel" :logLevel }; return nodeArgs; diff --git a/lib/driver/selenium.js b/lib/driver/selenium.js index 6c5e37a0..e5e55882 100644 --- a/lib/driver/selenium.js +++ b/lib/driver/selenium.js @@ -63,7 +63,7 @@ util.inherits(SeleniumDriver, Driver); SeleniumDriver.prototype.errorCheck = function (e, callback) { var self = this, errorMessage = e.toString(), match = false, matchErrorMessage = function (regex, group) { - var m = errorMessage.match(/([^\n\r]*)[\n|\r]?([\w\W]*)/), line, ret; + var m = errorMessage.match(/([^\n\r]*)[\n|\r]?([\w\W]*)/), ret; if (group) { ret = m ? m[group].match(regex) : undefined; } else { @@ -257,8 +257,6 @@ SeleniumDriver.prototype.createDriverJs = function (testParams, callback) { scriptType = "test", testJs, testJsUrl = "", - actionJs, - actionJsUrl = "", testParamsJs, yuiruntime = "", appSeedUrl, @@ -311,12 +309,8 @@ SeleniumDriver.prototype.createDriverJs = function (testParams, callback) { }; testJs = testParams.test; - actionJs = testParams.action; - if (!testJs && !actionJs) { - return callback("The test or the action js must be specified"); - } - if (actionJs) { - scriptType = "action"; + if (!testJs) { + return callback("The test js must be specified"); } appSeedUrl = self.config["defaultAppSeed"]; @@ -398,7 +392,7 @@ SeleniumDriver.prototype.createDriverJs = function (testParams, callback) { }; try { for (i = 0; i < arrLib.length; i += 1) { - lib = arrLib[i]; + lib = arrLib[i].trim(); if (0 === lib.length) { continue; } @@ -420,9 +414,6 @@ SeleniumDriver.prototype.createDriverJs = function (testParams, callback) { if (testJs) { self.logger.info("Loading test: " + testJs + " from " + this.args.relativePath); testJs = resolvePath(testJs); - } else { - self.logger.info("Loading action: " + actionJs + " from " + this.args.relativePath); - testJs = resolvePath(actionJs); } testLibsJs += fs.readFileSync(testJs, "utf-8"); @@ -521,7 +512,6 @@ SeleniumDriver.prototype.createDriverJs = function (testParams, callback) { "ARROW.testLibs = " + testLibsUrl + ";" + "ARROW.scriptType = \"" + scriptType + "\";" + "ARROW.testScript = \"" + testJsUrl + "\";" + - "ARROW.actionScript = \"" + actionJsUrl + "\";" + "ARROW.engineConfig = " + engineConfig + ";" + "ARROW.onSeeded = function() { " + testLibsJs + " };" + seedJs; @@ -562,13 +552,14 @@ SeleniumDriver.prototype.createDriverJs = function (testParams, callback) { /** * Driver interface method, called by controllers * - * @param page + * @param testParams parameters for this test * @params callback function to call once navigated */ -SeleniumDriver.prototype.navigate = function (page, callback) { +SeleniumDriver.prototype.navigate = function (testParams, callback) { var self = this, logger = this.logger, webdriver = this.webdriver, + page = testParams.page, url; self.logger.debug("Loading page in navigate: " + page); self.logger.info("Loading page: " + page); @@ -581,9 +572,7 @@ SeleniumDriver.prototype.navigate = function (page, callback) { } else { // timeout is not implemented for mobile devices - if (!this.isMobile) { - webdriver.manage().window().maximize(); - } + self.resizeWindow(testParams.windowSize); self.logger.debug("Getting url:" + url); webdriver.get(url).then(function () { self.logger.debug("callback of webdriver get"); @@ -596,105 +585,6 @@ SeleniumDriver.prototype.navigate = function (page, callback) { }; -/** - * Driver interface method, called by controllers - * - * @param testConfig values from the config section in the descriptor ycb - * @param testParams parameters for this test - * @params callback function to call at the end of the test with errorMsg - */ -SeleniumDriver.prototype.executeAction = function (testConfig, testParams, callback) { - var self = this, - logger = this.logger, - webdriver = this.webdriver, - actionJs, - page, - driverJs, - retryCount = 0, - url; - - actionJs = testParams.action; - page = testParams.page; - if (!testParams.lib && self.args.params && self.args.params.lib) { - testParams.lib = self.args.params.lib; - } - self.testCallback = callback; // save it so that async wd exception can be reported back - - function finializeAction(actionData) { - logger.debug("Finalizing action"); - webdriver.executeScript("ARROW.actionReported = true;").then(function () { - webdriver.waitForNextPage().then(function () { - callback(null, actionData); - }, function(err) { - self.logger.error('finalizeAction: webdriver.executeScript error : url - ' + url + ' ,error - ' + err); - self.errorCallback(logger, 'webdriver.executeScript error : url - ' + url + ' ,error - ' + err, callback); - }); - }); - } - - function collectActionReport() { - var reportJson; - - retryCount += 1; - logger.debug("Waiting for the action to finish, attempt: " + retryCount); - webdriver.executeScript("return ARROW.actionReport;").then(function (report) { - if (report) { - reportJson = JSON.parse(report); - if (reportJson.error) { - self.logger.error("Action error: " + reportJson.error); - self.errorCallback(logger, "Failed to execute the action: " + actionJs, callback); - } else { - finializeAction(report.data); - } - } else if (retryCount > self.maxAttempt) { - self.errorCallback(logger, "Failed to execute the action", callback); - } else { - setTimeout(collectActionReport, self.attemptInterval); - } - }, function(err) { - self.logger.error('collectActionReport: webdriver.executeScript error : ' + err); - self.errorCallback(logger, 'Error in executing script : ' + err, callback); - }); - } - - function initAction() { - webdriver.executeScript(driverJs).then(function () { - setTimeout(collectActionReport, self.attemptInterval); - }, function(err) { - self.logger.error('initAction:webdriver.executeScript error : ' + err); - self.errorCallback(logger, 'Error in executing script : ' + err, callback); - }); - } - - this.createDriverJs(testParams, function (err, driverjs) { - if (err) { - return callback(err); - } - driverJs = driverjs; - if (page) { - self.logger.info("Loading page: " + page); - if (!self.isMobile) { - webdriver.manage().window().maximize(); - } - - // local paths need to be served via test server - url = self.getRemoteUrl(page); - if (false === url) { - self.errorCallback(logger, "Cannot load a local file without arrow_server running: " + page, callback); - } else { - webdriver.get(url).then(function () { - initAction(); - }, function(err) { - self.logger.error('createDriverJs:webdriver.get : ' + err); - self.errorCallback(logger, 'Error in getting url - ' + url + ' : ' + err, callback); - }); - } - } else { - initAction(); - } - }); -}; - /** * Driver interface method, called by controllers * @@ -731,6 +621,10 @@ SeleniumDriver.prototype.executeTest = function (testConfig, testParams, callbac webdriver.getCurrentUrl().then(function (u) { reportJson = JSON.parse(report); reportJson.currentUrl = u; + if (self.sauceLabsSessionId) { + reportJson.sauceLabsReportUrl = 'http://saucelabs.com/jobs/' + + self.sauceLabsSessionId; + } self.addReport(JSON.stringify(reportJson), caps); }, function(err) { self.logger.error('collectTestReport:webdriver.getCurrentUrl - ' + err); @@ -857,17 +751,22 @@ SeleniumDriver.prototype.executeTest = function (testConfig, testParams, callbac self.logger.debug("Minified Driver js: " + driverJs); } webdriver.getCapabilities().then(function (val) { - logger.debug(JSON.stringify(val)); if (!val) { self.errorCallback(logger, "Unable to get a valid session, check your selenium config", callback); return; } + logger.debug(JSON.stringify(val)); + + if (self.config.isSauceLabs) { + if (val.caps_ && val.caps_['webdriver.remote.sessionid']) { + logger.debug('Got sauce labs session id'); + self.sauceLabsSessionId = val.caps_['webdriver.remote.sessionid']; + } + } caps = val; }); - if(!self.isMobile) { - webdriver.manage().window().maximize(); - } + self.resizeWindow(testParams.windowSize); // in case of html test, we need to load the test as a page if (".html" === path.extname(testJs)) { @@ -906,4 +805,15 @@ SeleniumDriver.prototype.executeTest = function (testConfig, testParams, callbac }); }; -module.exports = SeleniumDriver; \ No newline at end of file +SeleniumDriver.prototype.resizeWindow = function(windowSize) { + if (!this.isMobile) { + if (windowSize) { + this.webdriver.manage().window().setSize(parseInt(windowSize.width, 10), parseInt(windowSize.height, 10)); + this.webdriver.manage().window().setPosition(0, 0); + } else { + this.webdriver.manage().window().maximize(); + } + } +}; + +module.exports = SeleniumDriver; diff --git a/lib/engine/yuitest/yuitest-runner.js b/lib/engine/yuitest/yuitest-runner.js index 2e5da3a5..3b2ddda9 100644 --- a/lib/engine/yuitest/yuitest-runner.js +++ b/lib/engine/yuitest/yuitest-runner.js @@ -61,40 +61,6 @@ yuitestRunner.prototype.runRunner = function (cb) { var self = this; YUI({ useBrowserConsole: true }).use("get", function (Y) { - function loadAction() { - YUI({ useBrowserConsole: true }).use(ARROW.testBag, function (Y) { - var action = Y.arrow ? Y.arrow.action : null; - - if (!action) { - ARROW.actionReport = JSON.stringify({"error": "Could not find an action to execute"}); - return; - } - - try { - action.testParams = ARROW.testParams; - - action.setUp(function (error, data) { - var interval; - - ARROW.actionReport = JSON.stringify({"error": error, "data": data}); - if (error) { // we cannot execute the action - return; - } - // wait for the report to be collected before executing the action - // because actions are supposed to navigate away - interval = setInterval(function () { - if (ARROW.actionReported) { - clearInterval(interval); - action.execute(); - } - }, 100); - }); - } catch (ex) { - ARROW.actionReport = JSON.stringify({"error": "Exception: " + ex}); - } - }); - } - function runTest() { var YTest = YUITest, testRunner = YTest.TestRunner, @@ -138,18 +104,6 @@ yuitestRunner.prototype.runRunner = function (cb) { } } - function fetchAction(actionScript) { - if (actionScript.length > 0) { - Y.Get.script(actionScript, { - onSuccess: function (o) { - loadAction(); - } - }); - } else { - loadAction(); - } - } - function fetchTest(testScript) { if (testScript.length > 0) { Y.Get.script(testScript, { @@ -167,8 +121,6 @@ yuitestRunner.prototype.runRunner = function (cb) { if (ARROW.scriptType) { if ("test" === ARROW.scriptType) { fetchTest(ARROW.testScript); - } else { - fetchAction(ARROW.actionScript); } } else { fetchTest(ARROW.testScript); diff --git a/lib/engine/yuitest/yuitest-seed.js b/lib/engine/yuitest/yuitest-seed.js index c50f306d..a073df73 100644 --- a/lib/engine/yuitest/yuitest-seed.js +++ b/lib/engine/yuitest/yuitest-seed.js @@ -14,14 +14,10 @@ // ARROW.testLibs = []; // ARROW.scriptType = "test"; // ARROW.testScript = "test-file.js"; -// ARROW.actionScript = "action-file.js"; // ARROW.onSeeded = function() { /* add test, hand over to runner */} ARROW.testBag = ["test"]; ARROW.testReport = null; -ARROW.actionReport = null; -ARROW.actionReported = false; - var isCommonJS = typeof window === "undefined" && typeof exports === "object"; var seed = isCommonJS ? require('../interface/engine-seed').engineSeed : window.engineSeed; @@ -52,9 +48,6 @@ yuitestSeed.prototype.captureModuleTests = function (cb) { if (("test" === ARROW.scriptType) && (-1 !== name.indexOf("-tests"))) { //console.log("Found test module: " + name); ARROW.testBag.push(name); - } else if (("action" === ARROW.scriptType) && (-1 !== name.indexOf("-action"))) { - //console.log("Found test action: " + name); - ARROW.testBag.push(name); } }; }; diff --git a/lib/interface/driver.js b/lib/interface/driver.js index 3ea70618..c83e99f9 100644 --- a/lib/interface/driver.js +++ b/lib/interface/driver.js @@ -33,10 +33,6 @@ Driver.prototype.stop = function (callback) { if (callback) { callback(null); } }; -Driver.prototype.executeAction = function (testConfig, testArgs, callback) { - this.errorCallback(this.logger, "executeAction is not supported", callback); -}; - Driver.prototype.executeTest = function (testConfig, testArgs, callback) { this.errorCallback(this.logger, "executeTest must be implemented", callback); }; diff --git a/lib/proxy/proxymanager.js b/lib/proxy/proxymanager.js index a07c3065..5b840c2c 100644 --- a/lib/proxy/proxymanager.js +++ b/lib/proxy/proxymanager.js @@ -6,8 +6,7 @@ * See the accompanying LICENSE file for terms. */ -var http = require('http'), - log4js = require("log4js"), +var log4js = require("log4js"), fs = require('fs'), path = require('path'), portchecker = require("../../ext-lib/portchecker"), @@ -20,13 +19,9 @@ function ProxyManager(proxyConfig, config) { this.config = config || {}; this.proxyConfig = proxyConfig || {}; this.logger = log4js.getLogger("ProxyManager"); - if (global.workingDirectory) { - this.fileName = path.resolve(global.workingDirectory, "proxy.log"); - } else { - this.fileName = "proxy.log"; - } global.proxyManager = {}; global.proxyManager.record = []; + this.proxyLogFile = this.getProxyLogFileName(); } /** @@ -53,7 +48,7 @@ ProxyManager.prototype.recordTraffic = function(router, request, response) { if (router[reqHost] || router[onlyhost]) { if ((router[reqHost] && router[reqHost].record)) { - obj.push({"url": reqUrl, "headers": request.headers, "responseHeaders": response.headers, "method": request.method}); + obj.push({"url": reqUrl, "headers": request.headers, "responseHeaders": response.headers, "method": request.method, "body": request['body']}); global.proxyManager.record[self.proxyConfig] = obj; } @@ -61,6 +56,19 @@ ProxyManager.prototype.recordTraffic = function(router, request, response) { }; +/** + * Return the proxy log file name + * @returns {string} + */ +ProxyManager.prototype.getProxyLogFileName = function() { + + var proxyFile = "proxy.log"; + if (global.workingDirectory) { + proxyFile = global.workingDirectory ? path.resolve(global.workingDirectory, proxyFile) : proxyFile; + } + return proxyFile; +}; + /** * * @param router - proxy configuration defined in json file @@ -132,6 +140,11 @@ ProxyManager.prototype.runRouterProxy = function (minPort, maxPort, host, callba needsClientCoverage = false, tmpPath = require("../util/sharelibscanner").scannerUtil.getShareLibMetaPath(); + // Added for debugging + process.on('uncaughtException', function(err) { + self.logger.error("Uncaught exception in ProxyManager :" + err.stack); + }); + try { // Need to check/maintain how many descriptors require proxy.Set path for those descriptors at testSession level @@ -250,11 +263,17 @@ ProxyManager.prototype.runRouterProxy = function (minPort, maxPort, host, callba } } else { // to make compatible with old routeProxyConfig - var options, reqUrl, handle,f_http; + var options, reqUrl, handle,f_http, postBodyLimit = 0; options = self.getOptions(proxy_config.router || proxy_config, request); reqUrl = options.headers['reqUrl']; + // Try to setup a buffer for POST body to store. + if (proxy_config && proxy_config.storeBody) { + postBodyLimit = proxy_config && proxy_config.sizeLimit || 10240; + request['body'] = {text:''}; + } + proxy_coverage = proxy_config.coverage || {}; needsClientCoverage = proxy_coverage.clientSideCoverage; passthroughurls = proxy_coverage.coverageExclude || []; @@ -262,7 +281,7 @@ ProxyManager.prototype.runRouterProxy = function (minPort, maxPort, host, callba handle = options.headers['protocol'] === 'https:' ? 'https' : 'http'; f_http = require('./../../ext-lib/follow_redirect_http.js')[handle]; - options.agent = false; + f_http.globalAgent.maxSockets = 200; proxy_request = f_http.request(options, function (proxy_response) { @@ -442,7 +461,7 @@ ProxyManager.prototype.runRouterProxy = function (minPort, maxPort, host, callba } }); - self.writeLog(port + ":" + reqUrl + ":" + proxy_response.statusCode); + self.writeLog(p + ":" + reqUrl + ":" + proxy_response.statusCode); //(url, resHeaders) response.writeHead(proxy_response.statusCode, proxy_response.headers); @@ -451,6 +470,12 @@ ProxyManager.prototype.runRouterProxy = function (minPort, maxPort, host, callba }); request.addListener('data', function (chunk) { + //Store the POST body into the body object for tracking later. + if (proxy_config && proxy_config.storeBody) { + if (postBodyLimit > request['body']['text'].length) { + request['body']['text'] = (request['body']['text'] + chunk).substring(0, postBodyLimit); + } + } proxy_request.write(chunk, 'binary'); }); @@ -522,18 +547,20 @@ ProxyManager.prototype.runRouterProxy = function (minPort, maxPort, host, callba }; ProxyManager.prototype.writeLog = function (logLine) { - var StringDecoder = require('string_decoder').StringDecoder, decoder = new StringDecoder('utf8'), data = decoder.write(logLine + "\n"), - fd; + self = this; - fd = fs.openSync(this.fileName, 'a'); - fs.writeSync(fd, data); - fs.closeSync(fd); - -// fs.appendFileSync(this.fileName, data); + try { + if (self.proxyLogFile) { + fs.appendFileSync(self.proxyLogFile, data); + } + } + catch(e){ + self.logger.error('Exception in writing proxy log ' + e); + } }; module.exports = ProxyManager; \ No newline at end of file diff --git a/lib/session/sessionUtil.js b/lib/session/sessionUtil.js new file mode 100644 index 00000000..39ca0ffe --- /dev/null +++ b/lib/session/sessionUtil.js @@ -0,0 +1,61 @@ +/*jslint forin:true sub:true anon:true, sloppy:true, stupid:true nomen:true, node:true continue:true*/ + +/* + * Copyright (c) 2014, Yahoo! Inc. All rights reserved. + * Copyrights licensed under the New BSD License. + * See the accompanying LICENSE file for terms. + */ + +var log4js = require("log4js"); + +function SessionUtil() { + this.logger = log4js.getLogger("SessionUtil"); +} + +/** + * Iterates over the report and checks if there's any failed test case + * @param reports + * @returns {boolean} + */ +SessionUtil.prototype.isFail = function(reports) { + + var arrReport, + isFail = false, + j, + k, + results, + testJson; + + if (reports.scenario) { + arrReport = reports.scenario; + } else { + arrReport = reports.results; + } + + if (arrReport) { + if (arrReport.length === 0) { + isFail = true; + } else { + for (j = 0; j < arrReport.length; j = j + 1) { + if (reports.scenario) { + results = arrReport[j].results; + for (k = 0; k < results.length; k = k + 1) { + testJson = results[k]; + if (testJson.type === "report" && testJson.failed > 0) { + isFail = true; + } + } + } else { + testJson = arrReport[j]; + if (testJson.type === "report" && testJson.failed > 0) { + isFail = true; + } + } + } + } + } + return isFail; + +}; + +module.exports = SessionUtil; \ No newline at end of file diff --git a/lib/session/sessionfactory.js b/lib/session/sessionfactory.js index 80a707f2..becf30c0 100644 --- a/lib/session/sessionfactory.js +++ b/lib/session/sessionfactory.js @@ -7,16 +7,14 @@ */ var log4js = require("log4js"); -var TestSession = require("../session/testsession"); var DataProvider = require("../util/dataprovider"); var ReportManager = require("../util/reportmanager"); var LibManager = require('../util/libmanager'); +var SessionUtil = require('./sessionUtil'); var TestExecutor = require("../session/testexecutor"); -var clone = require('clone'); var coverage = require("../util/coverage"); var fs = require("fs"); var path = require("path"); -var os = require("os"); var Servermanager = require("../../arrow_server/arrowservermanager.js"); var PhantomJsSetup = require("../util/phantomJsSetup.js"); @@ -85,6 +83,8 @@ function SessionFactory(config, args) { this.proxyConfigList = []; + this.phantomJsSetup = PhantomJsSetup.getInstance(); + /* timeReportObj stores total time taken ,time taken for each descriptor as well as time taken for each test within the descriptor { "descriptors":[ @@ -167,158 +167,180 @@ SessionFactory.prototype.getFactoryTests = function () { x, y, i, + j, descFile, - relativePath; + relativePath, + testJsonArr, + isDataDriven, + qualifiedDescriptorPath, + descriptorPath; + // Iterate over all descriptor files and get the tests for (i = 0; i < this.arrDescriptor.length; i += 1) { - descFile = this.arrDescriptor[i]; //TODO : use path module here relativePath = descFile.substring(0, descFile.lastIndexOf(global.pathSep)); dpreader = new DataProvider(this.config, this.args,descFile); - testJson = dpreader.getTestData(); + testJsonArr = dpreader.getTestData(); - if (!this.descriptorObj[descFile]) { - this.descriptorObj[descFile] = {}; - this.descriptorObj[descFile].testSessionCount = 0; - } + for (j = 0; j < testJsonArr.length; j+=1) { - this.descriptorObj[descFile].testSuiteName = testJson.name; + testJson = testJsonArr[j]; + isDataDriven = (testJson && testJson.dataDriverKey) ? true : false; + descriptorPath = descFile; - //Check if the useSSL flag is set from either commandline or at descriptor level - if (testJson.useSSL) { - testJson = setSSL(testJson); - } else if (this.useSSL && testJson.useSSL != false) { - testJson = setSSL(testJson); - } + qualifiedDescriptorPath = descriptorPath; + if (isDataDriven){ + qualifiedDescriptorPath += (' - ' + testJson.dataDriverKey); + } - dp = testJson.dataprovider; - commonLib = testJson.commonlib; - testConfig = testJson.config; + if (!this.descriptorObj[qualifiedDescriptorPath]) { + this.descriptorObj[qualifiedDescriptorPath] = {}; + this.descriptorObj[qualifiedDescriptorPath].testSessionCount = 0; + } - if (this.browser) { - testJson.browser = this.browser; - } - this.logger.trace("runDataDrivenTest :"); - this.logger.trace(dp); - this.logger.trace("controller config :"); - this.logger.trace(testConfig); + this.descriptorObj[qualifiedDescriptorPath].dataDriverKey = testJson.dataDriverKey; + this.descriptorObj[qualifiedDescriptorPath].testSuiteName = testJson.name; -// this.descLib = ""; - if (commonLib) { - descLib = this.libManager.getAllTest(commonLib, relativePath); - } - - this.logger.trace("Desc Lib :" + descLib); - if (this.args.lib) { - if (descLib) { - descLib += "," + this.libManager.getAllTest(this.args.lib, ""); - } else { - descLib = this.libManager.getAllTest(this.args.lib, ""); + //Check if the useSSL flag is set from either commandline or at descriptor level + if (testJson.useSSL) { + testJson = this.setSSL(testJson); + } else if (this.useSSL && testJson.useSSL != false) { + testJson = this.setSSL(testJson); } - } - for (testName in dp) { - testData = dp[testName]; + dp = testJson.dataprovider; + commonLib = testJson.commonlib; + testConfig = testJson.config; - if (testData.enabled === null || false === testData.enabled || "false" === testData.enabled) { - this.logger.info("Disabled, skipping test: " + testName); - continue; + if (this.browser) { + testJson.browser = this.browser; } - if (this.group && !testData.group) { - this.logger.info("Group filtering : no group defined for test, skipping test: " + testName); - continue; + this.logger.trace("runDataDrivenTest :"); + this.logger.trace(dp); + this.logger.trace("controller config :"); + this.logger.trace(testConfig); + +// this.descLib = ""; + if (commonLib) { + descLib = this.libManager.getAllTest(commonLib, relativePath); } - if (this.group && testData.group) { - arrTestGroup = testData.group.split(","); - arrCommandLineGroup = this.group.split(","); + this.logger.trace("Desc Lib :" + descLib); + if (this.args.lib) { + if (descLib) { + descLib += "," + this.libManager.getAllTest(this.args.lib, ""); + } else { + descLib = this.libManager.getAllTest(this.args.lib, ""); + } + } - for (x in arrCommandLineGroup) { - for (y in arrTestGroup) { - if (arrCommandLineGroup[x] === arrTestGroup[y]) { - blnGroup = true; + for (testName in dp) { + testData = dp[testName]; + + if (testData.enabled === null || false === testData.enabled || "false" === testData.enabled) { + this.logger.info("Disabled, skipping test: " + testName); + continue; + } + if (this.group && !testData.group) { + this.logger.info("Group filtering : no group defined for test, skipping test: " + testName); + continue; + } + if (this.group && testData.group) { + + arrTestGroup = testData.group.split(","); + arrCommandLineGroup = this.group.split(","); + + for (x in arrCommandLineGroup) { + for (y in arrTestGroup) { + if (arrCommandLineGroup[x] === arrTestGroup[y]) { + blnGroup = true; + } } } - } - if (blnGroup) { - //console.log("MATCH"); - blnGroup = false; - } else { - this.logger.info("Test Group :" + testData.group); - this.logger.info("CommandLine Group :" + this.group); - this.logger.info("Group filtering, skipping test: " + testName); + if (blnGroup) { + //console.log("MATCH"); + blnGroup = false; + } else { + this.logger.info("Test Group :" + testData.group); + this.logger.info("CommandLine Group :" + this.group); + this.logger.info("Group filtering, skipping test: " + testName); + continue; + } + } + if (this.testName && (this.testName !== testName)) { + this.logger.info("TestName filtering, skipping Test :" + testName); continue; } - } - if (this.testName && (this.testName !== testName)) { - this.logger.info("TestName filtering, skipping Test :" + testName); - continue; - } - // Set proxy configuration in test session - testData.startProxyServer = testJson.startProxyServer; - testData.proxyConfig = testJson.routerProxyConfig; - testData.testName = testName; - testData.config = testConfig; + // Set proxy configuration in test session + testData.startProxyServer = testJson.startProxyServer; + testData.proxyConfig = testJson.routerProxyConfig; + testData.testName = testName; + testData.config = testConfig; - if (!testData.params) { - testData.params = {}; - } - testData.driver = this.driver; // if passed by the user - if (!testData.browser) { - testData.browser = testJson.browser; - } - if (testData.params.lib) { - testInstanceLib = this.libManager.getAllTest(testData.params.lib, relativePath); - if (testInstanceLib) { - if (descLib) { - testData.params.lib = descLib + "," + testInstanceLib; + if (!testData.params) { + testData.params = {}; + } + testData.driver = this.driver; // if passed by the user + if (!testData.browser) { + testData.browser = testJson.browser; + } + if (testData.params.lib) { + if (testData.relativePath) { + testInstanceLib = this.libManager.getAllTest(testData.params.lib, testData.relativePath); + } else { + testInstanceLib = this.libManager.getAllTest(testData.params.lib, relativePath); + } + if (testInstanceLib) { + if (descLib) { + testData.params.lib = descLib + "," + testInstanceLib; + } else { + testData.params.lib = testInstanceLib; + } } else { - testData.params.lib = testInstanceLib; + testData.params.lib = descLib; } } else { testData.params.lib = descLib; } - } else { - testData.params.lib = descLib; - } - - // Store relativePath of the json file, if not already set [ Will be set already in case of imported descriptor ] - if (!testData.relativePath) { - testData.relativePath = path.dirname(descFile); - } + // Store relativePath of the json file, if not already set [ Will be set already in case of imported descriptor ] + if (!testData.relativePath) { + testData.relativePath = path.dirname(descFile); + } + // Store the descriptor file name ( with path and test name & keys ( if data drive)) in testSession object + testData.qualifiedDescriptorPath = qualifiedDescriptorPath; + testData.descriptorPath = descriptorPath; - // Store the descriptor file name ( with path ) in testSession object - testData.descriptorPath = descFile; + if (this.descriptorObj[qualifiedDescriptorPath]) { + this.descriptorObj[qualifiedDescriptorPath].testSessionCount = 0; + } - // Store the no. of test sessions in the descriptor -// if (this.descriptorObj[descFile]) { -// this.descriptorObj[descFile].testSessionCount += 1; -// } else { -// this.descriptorObj[descFile].testSessionCount = 1; -// } + // Initialize the share area + testData.params.shared = {}; - if (this.descriptorObj[descFile]) { - this.descriptorObj[descFile].testSessionCount = 0; - } + if (testData.config && testData.config.descriptorSharedParams) { + testData.params.descriptorSharedParams = testData.config.descriptorSharedParams; + } else { + testData.params.descriptorSharedParams = {}; + } - // Initialize the share area - testData.params.shared = {}; + tests.push(testData); - tests.push(testData); + } } + } + return tests; }; SessionFactory.prototype.tearDown = function (testQueue, wdSessions) { - - var reportObj, + var reportObj = {}, reportManager, covFile, i, @@ -333,7 +355,8 @@ SessionFactory.prototype.tearDown = function (testQueue, wdSessions) { totalTimeTaken = ((Date.now() - global.startTime) / 1000).toFixed(2); if (this.args.report && testQueue.sessions) { - if (this.arrDescriptor && this.arrDescriptor.length > 1) { + // Show consolidated reports only when more than 1 descriptors + if (this.descriptorObj && Object.keys(this.descriptorObj).length > 1) { showConsolidatedReport = true; } @@ -357,9 +380,8 @@ SessionFactory.prototype.tearDown = function (testQueue, wdSessions) { } if (global.reportFolder) { - reportObj = { - "timeReport" : this.timeReportObj - }; + + reportObj.timeReport = this.timeReportObj; reportManager = new ReportManager(reportObj); reportManager.totalTimeTaken = totalTimeTaken; reportManager.writeTimeReport(); @@ -400,17 +422,56 @@ SessionFactory.prototype.tearDown = function (testQueue, wdSessions) { Servermanager.stopArrowServer(true); } - if (this.config.startPhantomJs === true) { - PhantomJsSetup.stopPhantomJs(); + if (this.config.startPhantomJs === true || this.config['phantomHost']) { + this.phantomJsSetup.stopPhantomJs(); } if (global.workingDirectory) { + failed = false; if (this.args.exitCode === true) { - failed = global.failedDescriptors.length > 0; + failed = this.isFailure(reportObj); } + process.exit(failed ? 1 : 0); } }; +/** + * Returns true, if a failure is found in the reportObj + * @param reportObj + * @returns {boolean} + */ +SessionFactory.prototype.isFailure = function (reportObj) { + + var s, + session, + report, + self = this, + sessionUtil = new SessionUtil(), + isFail = false; + + if (reportObj && reportObj.arrTestSessions) { + + for (var s in reportObj.arrTestSessions) { + + try { + session = reportObj.arrTestSessions[s]; + report = session.driver.reports.report; + isFail = sessionUtil.isFail(report); + if (isFail) { + self.logger.debug('Exiting with non-zero failure code'); + return true; + } + } + catch(e) { + self.logger.error('Error while looking for failures in test report : ' + e); + } + + } + } + return false; + +}; + module.exports = SessionFactory; diff --git a/lib/session/testexecutor.js b/lib/session/testexecutor.js index a9a4c01a..204d41f4 100644 --- a/lib/session/testexecutor.js +++ b/lib/session/testexecutor.js @@ -6,16 +6,13 @@ * See the accompanying LICENSE file for terms. */ var log4js = require("log4js"); -var SessionFactory = require("./sessionfactory"); var ReportManager = require("../util/reportmanager"); -var FileUtil = require("../util/fileutil"); var WdSession = require("../session/wdsession"); var TestSession = require("../session/testsession"); var ProxyManager = require("../proxy/proxymanager"); var clone = require('clone'); var path = require("path"); var os = require("os"); -var fs = require("fs"); var async = require("async"); var sf; @@ -46,13 +43,12 @@ TestExecutor.prototype.writeReportForDescriptor = function(testSession, callback var descriptor, testSessionsArr, - currTime, reportObj, reportManager; for (descriptor in sf.descriptorObj) { - if (descriptor === testSession.descriptorPath) { + if (descriptor === testSession.qualifiedDescriptorPath) { // Store testSessions array for each descriptor in testSessionMap if (sf.testSessionMap[descriptor]) { testSessionsArr = sf.testSessionMap[descriptor]; @@ -66,13 +62,14 @@ TestExecutor.prototype.writeReportForDescriptor = function(testSession, callback sf.descriptorObj[descriptor].testSessionCount -= 1; if (sf.descriptorObj[descriptor].testSessionCount === 0) { - sf.timeReportObj[testSession.descriptorPath].endTime = Date.now(); // TODO Is endTime required ??? - sf.timeReportObj[testSession.descriptorPath].timeTaken = - ((sf.timeReportObj[testSession.descriptorPath].endTime - sf.timeReportObj[testSession.descriptorPath].startTime) / 1000).toFixed(2); + sf.timeReportObj[testSession.qualifiedDescriptorPath].endTime = Date.now(); // TODO Is endTime required ??? + sf.timeReportObj[testSession.qualifiedDescriptorPath].timeTaken = + ((sf.timeReportObj[testSession.qualifiedDescriptorPath].endTime - sf.timeReportObj[testSession.qualifiedDescriptorPath].startTime) / 1000).toFixed(2); - testExecutor.logger.info('Time taken to run descriptor-' + testSession.descriptorPath + ' = ' + sf.timeReportObj[testSession.descriptorPath].timeTaken); + testExecutor.logger.info('Time taken to run descriptor-' + testSession.qualifiedDescriptorPath + ' = ' + sf.timeReportObj[testSession.qualifiedDescriptorPath].timeTaken); + + testExecutor.logger.info('All tests over for descriptor:' + testSession.qualifiedDescriptorPath); - testExecutor.logger.info('All tests over for descriptor:' + testSession.descriptorPath); reportObj = { "reportFolder" : global.reportFolder, "arrTestSessions" : sf.testSessionMap[descriptor], @@ -82,11 +79,11 @@ TestExecutor.prototype.writeReportForDescriptor = function(testSession, callback "driver" : sf.driver, "browser" : sf.browser, "group" : sf.args.group, - "testName" : sf.args.testName - + "testName" : sf.args.testName, + "dataDriverKey":sf.descriptorObj[descriptor].dataDriverKey }; reportManager = new ReportManager(reportObj); - reportManager.totalTimeTaken = sf.timeReportObj[testSession.descriptorPath].timeTaken; + reportManager.totalTimeTaken = sf.timeReportObj[testSession.qualifiedDescriptorPath].timeTaken; reportManager.writeReports(); } @@ -144,9 +141,9 @@ TestExecutor.prototype.runNextTest = function(testQueue) { testQueue.curIndex += 1; // If first test session is starting for the descriptor, note start time - if (!sf.timeReportObj[testSession.descriptorPath]) { - sf.timeReportObj[testSession.descriptorPath] = []; - sf.timeReportObj[testSession.descriptorPath].startTime = Date.now(); + if (!sf.timeReportObj[testSession.qualifiedDescriptorPath]) { + sf.timeReportObj[testSession.qualifiedDescriptorPath] = []; + sf.timeReportObj[testSession.qualifiedDescriptorPath].startTime = Date.now(); } testSession.runTest(function (error) { @@ -163,8 +160,8 @@ TestExecutor.prototype.runNextTest = function(testQueue) { // Write report per descriptor ( if all testsessions for the descriptor ( to which the current test session belongs ) are run ) - if (sf.timeReportObj[thisSession.descriptorPath].testSessionTimeArr) { - testSessionTimeArr = sf.timeReportObj[thisSession.descriptorPath].testSessionTimeArr; + if (sf.timeReportObj[thisSession.qualifiedDescriptorPath].testSessionTimeArr) { + testSessionTimeArr = sf.timeReportObj[thisSession.qualifiedDescriptorPath].testSessionTimeArr; } else { testSessionTimeArr = {}; } @@ -172,9 +169,9 @@ TestExecutor.prototype.runNextTest = function(testQueue) { testSessionTimeArr[thisSession.args.testName] = {}; testSessionTimeArr[thisSession.args.testName].timeTaken = ((thisSession.endTime - thisSession.startTime) / 1000).toFixed(2); - sf.timeReportObj[thisSession.descriptorPath].testSessionTimeArr = testSessionTimeArr; + sf.timeReportObj[thisSession.qualifiedDescriptorPath].testSessionTimeArr = testSessionTimeArr; - testExecutor.logger.info('Time taken to run - ' + thisSession.descriptorPath + '-' + thisSession.args.testName + ' is::' + + testExecutor.logger.info('Time taken to run - ' + thisSession.qualifiedDescriptorPath + '-' + thisSession.args.testName + ' is::' + testSessionTimeArr[thisSession.args.testName].timeTaken); testExecutor.writeReportForDescriptor(thisSession, function() { @@ -209,11 +206,11 @@ TestExecutor.prototype.setupTestQueues = function(callback) { i, j; function incrementTestSessionCount(test) { - if (test.descriptorPath) { - if (sf.descriptorObj[test.descriptorPath]) { - sf.descriptorObj[test.descriptorPath].testSessionCount += 1; + if (test.qualifiedDescriptorPath) { + if (sf.descriptorObj[test.qualifiedDescriptorPath]) { + sf.descriptorObj[test.qualifiedDescriptorPath].testSessionCount += 1; } else { - sf.descriptorObj[test.descriptorPath].testSessionCount = 1; + sf.descriptorObj[test.qualifiedDescriptorPath].testSessionCount = 1; } } diff --git a/lib/session/testsession.js b/lib/session/testsession.js index 332cb309..62da4016 100644 --- a/lib/session/testsession.js +++ b/lib/session/testsession.js @@ -6,13 +6,16 @@ * See the accompanying LICENSE file for terms. */ -var http = require("http"); var log4js = require("log4js"); var Arrow = require("../interface/arrow"); var fs = require('fs'); var path = require('path'); var FileUtil = require("../util/fileutil"); +var SessionUtil = require("./sessionUtil"); +var SauceLabsUtil = require("../util/sauceLabsUtil"); +var CapabilityManager = require("../util/capabilitymanager"); var existsSync = fs.existsSync || path.existsSync; +var PhantomJsSetup = require("../util/phantomJsSetup.js"); function TestSession(config, args, sessionId) { this.logger = log4js.getLogger("TestSession"); @@ -38,6 +41,10 @@ function TestSession(config, args, sessionId) { this.descriptorPath = args.descriptorPath; } + if (args.qualifiedDescriptorPath) { + this.qualifiedDescriptorPath = args.qualifiedDescriptorPath; + } + this.startTime = 0; this.endTime = 0; if (args.resolvedProxyConfigPath) { @@ -72,12 +79,12 @@ TestSession.prototype.setup = function (callback) { return; } if (this.resolvedProxyConfigPath) { - this.logger.debug("ResolvedProxyConfig path for " + this.descriptorPath + " is :" + this.resolvedProxyConfigPath); + this.logger.debug("ResolvedProxyConfig path for " + this.qualifiedDescriptorPath + " is :" + this.resolvedProxyConfigPath); this.args.proxyUrl = global.routerMap[this.resolvedProxyConfigPath]; try { this.args.proxyConfig = require(this.resolvedProxyConfigPath); } catch (e) { - this.logger.debug("Exception in resolving " + this.resolvedProxyConfigPath + " : " + e); + this.logger.error("Exception in resolving " + this.resolvedProxyConfigPath + " : " + e); } } @@ -130,14 +137,31 @@ TestSession.prototype.runTest = function (callback) { }; +/** + * Record test failure and rerun the failed test + * @param callback + * @param error + */ TestSession.prototype.retryTest = function (callback, error) { - var self = this; + var self = this, + isTestPassed, + isSauceLabs; + self.retryCount += 1; - // checking if there is a yui test failures : self.isFail() + isTestPassed = error || self.isFail(); + isSauceLabs = self.config.isSauceLabs; + + var cm = new CapabilityManager(); + var browser = self.args["browser"] + || self.config["browser"]; + + var capabilities = cm.getCapabilities(self.args, self.config); + + // checking if there is a test failures : self.isFail() // or if there is a failure at controller level : error - if (error || self.isFail()) { + if (isTestPassed) { // if retryCount is provided, and retries are left for this test, lets record the failure and retry the test if (global.retryCount - self.retryCount >= 0) { self.logger.debug('Recording failure before retrying'); @@ -145,66 +169,102 @@ TestSession.prototype.retryTest = function (callback, error) { self.logger.debug('Before stopping'); self.driver.stop(function() { self.logger.info("\nRetrying Test, Attempt #" + self.retryCount); - self.runTest(callback); + self.reRunSetup(function(){ + self.runTest(callback); + }); + }); }); } else { - self.logger.debug('Recording failure before retrying'); + self.logger.debug('Recording failure'); self.recordFailure(self.retryCount, function() { - self.driver.stop(callback, error); + if (isSauceLabs) { + + self.updateSauceLabs(false, self.args.testName, + self.driver.sauceLabsSessionId, + capabilities.username, + capabilities.accessKey, + self.logger, + function(){ + self.driver.stop(callback, error); + }); + + } else { + self.driver.stop(callback, error); + } }); } } else { - self.driver.stop(callback); + if (isSauceLabs) { + + self.updateSauceLabs(true, self.args.testName, + self.driver.sauceLabsSessionId, + capabilities.username, + capabilities.accessKey, + self.logger, + function(){ + self.driver.stop(callback, error); + }); + + } else { + self.driver.stop(callback); + } } }; +/** + * Update sauce labs result + * @param passed + * @param testName + * @param sessionId + * @param username + * @param accessKey + * @param callback + */ +TestSession.prototype.updateSauceLabs = function(result, + testName, + sessionId, + username, + accessKey, + logger, + callback) { + + var sauceLabsUtil = new SauceLabsUtil(); + + sauceLabsUtil.updateJobStatus({"passed":result, "name": testName}, + sessionId, + username, + accessKey, + function(err){ + if (err) { + logger.debug('Error in updating sauce labs pass result status - ' + err); + } else { + logger.debug('Successfully updated sauce labs pass result status'); + } + // If failed to update sauce labs , log it but don't pass back + callback(null); + return; + }); +}; + +/** + * Check for failures in test report + * @returns {boolean} + */ TestSession.prototype.isFail = function () { - var arrReport, + var rep, - j, - k, - isFail = false, self = this, - results, - testJson; + sessionUtil = new SessionUtil(); //checking if there was any failure rep = self.driver.getReports(); - if (rep.scenario) { - arrReport = rep.scenario; - } else { - arrReport = rep.results; - } - - if (arrReport) { - if (arrReport.length === 0) { - isFail = true; - } else { - for (j = 0; j < arrReport.length; j = j + 1) { - if (rep.scenario) { - results = arrReport[j].results; - for (k = 0; k < results.length; k = k + 1) { - testJson = results[k]; - if (testJson.type === "report" && testJson.failed > 0) { - isFail = true; - } - } - } else { - testJson = arrReport[j]; - if (testJson.type === "report" && testJson.failed > 0) { - isFail = true; - } - } - } - } - } - return isFail; + return sessionUtil.isFail(rep); }; /** * - * @param artifactsObj : fields - testName ,count , descriptorPath , reportDir , screenShotsDir , artifactsUrl + * @param artifactsObj : fields - testName ,count , qualifiedDescriptorPath , reportDir , screenShotsDir , artifactsUrl * @returns {{}} - Object of Img and Html paths for screenshots - both relative and absolute */ TestSession.prototype.getArtifactPaths = function (artifactsObj){ @@ -220,7 +280,7 @@ TestSession.prototype.getArtifactPaths = function (artifactsObj){ try { - dirPath = artifactsObj.descriptorPath ? artifactsObj.descriptorPath : ""; + dirPath = artifactsObj.qualifiedDescriptorPath ? artifactsObj.qualifiedDescriptorPath : ""; dirPath = path.resolve(artifactsObj.reportDir, artifactsObj.screenShotsDir, dirPath); screenShotsPath = artifactsObj.screenShotsDir; @@ -235,10 +295,10 @@ TestSession.prototype.getArtifactPaths = function (artifactsObj){ if (artifactsObj.artifactsUrl) { // Note - artifactsUrl comes appended with reportFolder ( from ArrowSetup ). So no need to append reportDir again - artifactPaths.pngPath = artifactsObj.artifactsUrl + path.sep + path.join(screenShotsPath, artifactsObj.descriptorPath, screenShotImgPath); + artifactPaths.pngPath = artifactsObj.artifactsUrl + path.sep + path.join(screenShotsPath, artifactsObj.qualifiedDescriptorPath, screenShotImgPath); artifactPaths.pngPath = encodeURI(artifactPaths.pngPath); - artifactPaths.htmlPath = artifactsObj.artifactsUrl + path.sep + path.join(screenShotsPath, artifactsObj.descriptorPath, screenShotHtmlPath); + artifactPaths.htmlPath = artifactsObj.artifactsUrl + path.sep + path.join(screenShotsPath, artifactsObj.qualifiedDescriptorPath, screenShotHtmlPath); artifactPaths.htmlPath = encodeURI(artifactPaths.htmlPath); } else { @@ -252,8 +312,13 @@ TestSession.prototype.getArtifactPaths = function (artifactsObj){ return artifactPaths; -} +}; +/** + * + * @param count + * @param callback + */ TestSession.prototype.recordFailure = function (count, callback) { var webdriver = this.driver.webdriver, @@ -276,8 +341,10 @@ TestSession.prototype.recordFailure = function (count, callback) { reportDir = ( global.reportFolder === '') ? arrowTargetDir :global.reportFolder; - if (testName) { - testName = "arrow-" + this.args.testName; + testName = "arrow-"; + + if (self.args && self.args.testName) { + testName = "arrow-" + self.args.testName; } else { testName = "arrow"; } @@ -286,6 +353,7 @@ TestSession.prototype.recordFailure = function (count, callback) { artifactsObj.testName = testName; artifactsObj.count = count; artifactsObj.descriptorPath = self.descriptorPath; + artifactsObj.qualifiedDescriptorPath = self.qualifiedDescriptorPath; artifactsObj.reportDir = reportDir; artifactsObj.screenShotsDir = screenShotsDir; artifactsObj.artifactsUrl = global.artifactsUrl; @@ -383,6 +451,42 @@ TestSession.prototype.recordFailure = function (count, callback) { } }; +/** + * + * @param callback + */ +TestSession.prototype.reRunSetup = function(callback) { + + var self = this, + phantomJsSetup = PhantomJsSetup.getInstance(); + // If phantomJs is crashed, restart it and continue with tests + if (self.args.browser === "phantomjs") { + self.logger.debug('Check if PhantomJs is running'); + + phantomJsSetup.isPhantomJsRunning(function(isPhantomJsRunning){ + if (isPhantomJsRunning === false) { + // Start phantomJs before running the test + phantomJsSetup.startPhantomJs(self.config.ignoreSslErrorsPhantomJs, function(phantomHost){ + + // Exit if phantomJs could not be started + if (!phantomHost) { + self.logger.fatal('Could not start phantomjs. Exiting.'); + process.exit(1); + } + + self.config["phantomHost"] = phantomHost; + callback(); + }) + } else { + callback(); + } + }) + + } else { + callback(); + } +} + TestSession.prototype.isMobile = function (browserName) { var supportedMobileBrowserNames = ["iphone", "ipad", "android", "androidphone", "androidtablet"], diff --git a/lib/util/arrowsetup.js b/lib/util/arrowsetup.js index 353c3457..316c9ad5 100644 --- a/lib/util/arrowsetup.js +++ b/lib/util/arrowsetup.js @@ -11,7 +11,6 @@ var glob = require("glob"); var path = require('path'); var url = require('url'); var async = require('async'); -var Properties = require("../util/properties"); var log4js = require("log4js"); var LibManager = require('../util/libmanager'); var FileUtil = require("../util/fileutil"); @@ -21,7 +20,6 @@ var Servermanager = require("../../arrow_server/arrowservermanager.js"); var BrowserManager = require("./browserManager.js"); function ArrowSetup(config, argv) { - var __dirname = global.appRoot; this.config = config; this.argv = argv; } @@ -387,6 +385,12 @@ ArrowSetup.prototype.setupSeleniumHost = function (cb) { // setup the selenium host using the auto hookup if possible wdHubHost = this.config["seleniumHost"]; + + // If using sauce labs, set isSauceLabs to true + if (wdHubHost.indexOf(self.config.sauceLabsHost) > -1) { + self.config.isSauceLabs = true; + } + if (0 === wdHubHost.length) { // check if we have a hooked up server try { @@ -559,8 +563,8 @@ ArrowSetup.prototype.startPhantomJs = function(cb) { self.logger.trace('startPhantomJs starts'); if (this.config.startPhantomJs) { - - PhantomJsSetup.startPhantomJs(self.config.ignoreSslErrorsPhantomJs, function(phantomHost) { + var phantomJsSetup = PhantomJsSetup.getInstance(); + phantomJsSetup.startPhantomJs(self.config.ignoreSslErrorsPhantomJs, function(phantomHost) { self.logger.trace('startPhantomJs ends..' + phantomHost); if (!phantomHost) { diff --git a/lib/util/capabilitymanager.js b/lib/util/capabilitymanager.js index 4f88fa8a..5bbbe10f 100644 --- a/lib/util/capabilitymanager.js +++ b/lib/util/capabilitymanager.js @@ -8,13 +8,20 @@ var log4js = require("log4js"); var fs = require("fs"); +var _ = require("underscore"); var clone = require("clone"); function CapabilityManager() { this.logger = log4js.getLogger("CapabilityManager"); } -CapabilityManager.prototype.getCapability = function (capJsonPath, capName) { +/** + * + * @param caps - JSON blob or path to capabilities file + * @param capName - key to the caps object ,passed as browser from command line + * @returns {*} + */ +CapabilityManager.prototype.getCapability = function (caps, capName) { var capJson, cap, @@ -24,7 +31,7 @@ CapabilityManager.prototype.getCapability = function (capJsonPath, capName) { try { - capJson = JSON.parse(fs.readFileSync(capJsonPath, "utf-8")); + capJson = self.getCapsJSON(caps); cap = clone(capJson.capabilities[capName]); commonCap = capJson.common_capabilities; if (cap) { @@ -35,7 +42,7 @@ CapabilityManager.prototype.getCapability = function (capJsonPath, capName) { } } catch (e) { - self.logger.error('Error in parsing capabilities json -' + capJsonPath); + self.logger.error('Error in parsing capabilities json -' + caps); } @@ -43,23 +50,56 @@ CapabilityManager.prototype.getCapability = function (capJsonPath, capName) { }; +/** + * + * @param caps - Can be a JSON blob or filePath for capabilities file + * @returns {*} - JSON capabilities object + */ +CapabilityManager.prototype.getCapsJSON = function(caps) { + var capJson, + self = this; + + if (caps) { + + // If caps is JSON blob + try { + capJson = JSON.parse(caps); + return capJson; + } + catch(e) { + self.logger.debug('Error in parsing caps. It might be JSON file'); + } + + // If caps is file path containing JSON object + try { + capJson = JSON.parse(fs.readFileSync(caps, "utf-8")); + return capJson; + } + catch(e) { + self.logger.debug('Error in parsing capabilities JSON -' + caps); + } + } + + return null; + + +}; + +/** + * + * @param args + * @param config + * @returns {{platform: string, javascriptEnabled: boolean, seleniumProtocol: string}} + */ CapabilityManager.prototype.getCapabilities = function (args, config) { var self = this, caps = { - "platform": "ANY", +// "platform": "ANY", "javascriptEnabled": true, "seleniumProtocol": "WebDriver" - }, - tmpCaps, - browserInfo, - versionKey, - cm, - isProxyTest = false, - browserName, - browserVersion, - testName = args.testName; + }; caps.browserName = args["browser"] || config["browser"]; if (!caps.browserName) { @@ -67,15 +107,97 @@ CapabilityManager.prototype.getCapabilities = function (args, config) { return caps; } + // Set proxy capabilities + caps = self.setProxyCaps(caps, args); + + // Set browser capabilities + caps = self.setBrowserCaps(caps, args, config); + + // Set mobile browser capabilities + caps = self.setMobileCaps(caps); + + // Set sauce capabilities + caps = self.setSauceCaps(caps, config); + + // Process user capabilities + caps = self.processUserCapabilities(caps, config); + + self.logger.debug('To run the test ' + args.testName + ' with browser:' + caps.browserName + (caps.version ? ',version:' + caps.version : "")); + + return caps; + +}; + +/** + * Set device and app in capabilities for mobile browsers + */ +CapabilityManager.prototype.processUserCapabilities = function(caps, config) { + + var cm, + tmpCaps; + // if the user has passed capabilities as json + if (config.capabilities) { + cm = new CapabilityManager(); + tmpCaps = cm.getCapability(config.capabilities, caps.browserName); + if (tmpCaps === null) { + caps.error = "No related capability for " + caps.browserName + " in " + config.capabilities; + return caps; + } + + // Copy over tmpCaps to caps. Will over ride any default properties in caps and copy the extra ones + _.extend(caps,tmpCaps); + } + + return caps; + +}; + +/** + * Set device and app in capabilities for mobile browsers + */ +CapabilityManager.prototype.setMobileCaps = function(caps) { + + var browserName = caps.browserName.toLowerCase(); + + //extra properties required for appium + //ios case + if (browserName === "iphone" || browserName === "ipad") { + + caps.platformName = "iOS"; + caps.deviceName = browserName; + caps.browserName = "Safari"; + + // Remove version property if set to latest + if (caps.version === "latest") { + delete caps.version; + } + + //android case + } else if (browserName === "android" || browserName === "androidtablet") { + caps.device = browserName; + caps.app = "browser"; + } + return caps; + + +}; + +/** + * Set capabilities for proxy + * @param args + * @param caps + * @returns {*} + */ +CapabilityManager.prototype.setProxyCaps = function (caps, args) { + + var self = this; // For tests needing proxy server, set proxy flag if (args.proxyUrl) { if (args.proxy || args.proxy === undefined) { - isProxyTest = true; - // Add settings for proxy - self.logger.debug("Adding Proxy Setting to the Browser for the test " + testName); + self.logger.debug("Adding Proxy Setting to the Browser for the test " + args.testName); caps.proxy = { "httpProxy": args.proxyUrl, "sslProxy": args.proxyUrl, @@ -86,6 +208,23 @@ CapabilityManager.prototype.getCapabilities = function (args, config) { self.logger.debug("Descriptor overridden proxy param. Not setting proxy in browser"); } } + return caps; + +}; + +/** + * Set browserName and version + * @param caps + * @param config + * @param args + */ +CapabilityManager.prototype.setBrowserCaps = function (caps, args, config) { + + var browserInfo, + browserName, + browserVersion, + versionKey, + self = this; browserInfo = caps.browserName.split("-", 2); @@ -102,43 +241,39 @@ CapabilityManager.prototype.getCapabilities = function (args, config) { } // If browser is reuse and its a proxy test, set browser to firefox - if (caps.browserName === "reuse" && isProxyTest) { + if (caps.browserName === "reuse" && caps.proxy) { caps.browserName = "firefox"; caps.version = "latest"; - self.logger.debug(testName + " is a proxy test so can't use reuse. Setting browser to firefox."); + self.logger.debug(args.testName + " is a proxy test so can't use reuse. Setting browser to firefox."); } else { caps.browserName = browserName; caps.version = browserVersion; } - // if the user has passed capabilities as json - if (config.capabilities) { - cm = new CapabilityManager(); - tmpCaps = cm.getCapability(config.capabilities, caps.browserName); - if (tmpCaps === null) { - caps.error = "No related capability for " + caps.browserName + " in " + config.capabilities; - return caps; - } - caps = tmpCaps; - } - - self.logger.debug('To run the test ' + testName + ' with browser:' + caps.browserName + ',version:' + caps.version); - - browserName = caps.browserName.toLowerCase(); + return caps; - //extra properties required for appium - //ios case - if (browserName === "iphone" || browserName === "ipad") { - caps.device = browserName; - caps.app = "safari"; - //android case - } else if (browserName === "android" || browserName === "androidtablet") { - caps.device = browserName; - caps.app = "browser"; - } +}; - return caps; +/** + * Set capabilities for Saucelabs + * @param {Object} caps + * @param {Object} config + */ +CapabilityManager.prototype.setSauceCaps = function (caps, config) { + if (config.isSauceLabs) { + this.logger.debug('Setting capabilities for Saucelabs'); + caps.username = config.sauceUsername || process.env.SAUCE_USERNAME; + caps.accessKey = config.sauceAccesskey || process.env.SAUCE_ACCESS_KEY; + caps['parent-tunnel'] = config.sauceTunnel || process.env.SAUCE_TUNNEL; + this.logger.debug("Sauce username :" + caps.username); + if (caps['parent-tunnel']) { + this.logger.debug("Sauce tunnel :" + caps['parent-tunnel']); + } else { + this.logger.debug("Not using Sauce tunnel"); + } + } + return caps; }; module.exports = CapabilityManager; \ No newline at end of file diff --git a/lib/util/datadrivermanager.js b/lib/util/datadrivermanager.js new file mode 100644 index 00000000..00df55b7 --- /dev/null +++ b/lib/util/datadrivermanager.js @@ -0,0 +1,193 @@ +/*jslint forin:true sub:true anon:true, sloppy:true, stupid:true nomen:true, node:true continue:true*/ +/* + * Copyright (c) 2014, Yahoo! Inc. All rights reserved. + * Copyrights licensed under the New BSD License. + * See the accompanying LICENSE file for terms. + */ +var log4js = require("log4js"); +var fs = require("fs"); +var clone = require("clone"); +var path = require("path"); + +/** + * + * @constructor + */ +function DataDriverManager() { + this.logger = log4js.getLogger("DataDriverManager"); +} + +/** + * @param relativePath + * @param descriptorJson + * @returns {config} + */ +DataDriverManager.prototype.getConfigData = function (relativePath, descriptorJson) { + + var dataDriver, + dataDriverObj, + self = this, + proc = self.mock || process, + dataDriverPath, + configData; + + + if (descriptorJson[0].dataDriver) { + + try { + dataDriverPath = path.resolve(global.workingDirectory, relativePath, descriptorJson[0].dataDriver); + dataDriver = fs.readFileSync(dataDriverPath, "utf-8"); + dataDriverObj = JSON.parse(dataDriver); + } catch (e) { + self.logger.error('Error in getting config data from ' + dataDriverPath + ', error :' + e); + proc.exit(1); + } + configData = dataDriverObj.config; + + } else if (descriptorJson[0].config && descriptorJson[0].config.length > 0) { + configData = descriptorJson[0].config; + } + + return configData; + +}; + +/** + * + * @param testDataPath + * @param descriptorJson + * @returns {Array} + */ +DataDriverManager.prototype.processDataDriver = function (testDataPath, descriptorJson) { + + var + baseConfigArr, + self = this, + descriptorArr = [], + proc = self.mock || process, + relativePath = path.dirname(testDataPath), + i, + descJson; + + baseConfigArr = self.getConfigData(relativePath, descriptorJson); + + if (baseConfigArr && baseConfigArr.length > 0) { + + // Error out if duplicate keys exist in config data + try { + self.checkForDuplicateKeys(baseConfigArr); + } + catch(e) { + self.logger.error('Error while processing data driver for the descriptor:' + testDataPath + ' , Error ::' + e.message); + proc.exit(1); + } + + // Iterate per config in the base config array + for (i = 0; i < baseConfigArr.length; i += 1) { + + descJson = clone(descriptorJson); + + for (var key in baseConfigArr[i]) { + + // Set configuration for first element ( with "settings": [ "master" ] ) + var baseConfObj = baseConfigArr[i][key]; + descJson[0]['config'] = baseConfObj + descJson[0]['dataDriverKey'] = key; + + // Set configuration for rest of the elements ( with "settings": [ "environment:testing" ] for e.g ) + for (var j = 1; j < descJson.length; j+=1) { + + var configArr = descJson[j].config; + + if (configArr && configArr instanceof Array) { + var confObj = getObjectForKey(configArr, key); + descJson[j]['config'] = (confObj ? confObj : baseConfObj); + } + } + + } + + descriptorArr.push(descJson); + } + + /** + * + * + * If the input array is as below and key passed is "sports", + * [ + { + "news": { + "baseUrl" : "https://news.yahoo.com/", + "placeCls" : "lt", + "appCls" : "gta-news" + } + }, + { + "sports": { + "baseUrl" : "https://sports.yahoo.com/", + "placeCls" : "lt", + "appCls" : "gta-news" + } + } + ] + + it returns + { + "baseUrl" : "https://sports.yahoo.com/", + "placeCls" : "lt", + "appCls" : "gta-news" + } + + * @param jsonArr + * @param key + * @returns {*} + */ + function getObjectForKey(jsonArr, key) { + + if (jsonArr && jsonArr instanceof Array) { + + for (var i = 0 ; i < jsonArr.length; i+=1) { + + for (var k in jsonArr[i]) { + if (key === k) { + return jsonArr[i][k]; + } + } + } + + } + } + + } else { + self.logger.error('No configuration data found for the data driven descriptor..' + testDataPath); + proc.exit(1); + } + return descriptorArr; + +}; + +/** + * Checks for duplicate keys in the data driver. + * Exits with error message if finds duplicate keys + * @param configArr + */ +DataDriverManager.prototype.checkForDuplicateKeys = function (configArr) { + + var key, + keysArr = [], + self = this; + + for (var i = 0 ;i < configArr.length; i+=1 ) { + + for (key in configArr[i]) { + if (keysArr.indexOf(key) > -1) { + throw new Error("Invalid data for data driven descriptor. Duplicate key '" + key + "' in the object " + JSON.stringify(configArr[i])); + } else { + keysArr.push(key); + } + } + } + +}; + +module.exports = DataDriverManager; \ No newline at end of file diff --git a/lib/util/dataprovider.js b/lib/util/dataprovider.js index ccea5568..f399348c 100644 --- a/lib/util/dataprovider.js +++ b/lib/util/dataprovider.js @@ -7,16 +7,17 @@ */ var log4js = require("log4js"); -var os = require('os'); var fs = require("fs"); var qs = require('querystring'); var JSV = require("JSV").JSV; var ycb = require('ycb'); var path = require('path'); -var glob = require('glob'); +var _ = require("underscore"); var ImportManager = require("../util/importmanager"); -var ErrorManager = require("../util/errormanager"), -em = ErrorManager.getInstance(); +var ErrorManager = require("../util/errormanager"); +var DataDriverManager = require("../util/datadrivermanager"); +var em = ErrorManager.getInstance(); + function DataProvider(config, args, testDataPath) { @@ -31,32 +32,73 @@ function DataProvider(config, args, testDataPath) { this.defaultParamJSON = this.config.defaultParamJSON; } +/** + * + * @returns {Array} + */ DataProvider.prototype.getTestData = function () { var descriptorJson, - baseUrl, - pos, - dimensionsJson, - contextObj, descriptor, - descriptorSchema, - report, - baseJson, - relativePath, descriptorJsonStr, - proc = this.mock || process, - match, self = this, - importDescriptor, - cwd = global.workingDirectory || process.cwd(), - importManager = new ImportManager(); + descriptorArr = [], + dataDrivenDescriptorArr, + dataDriverManager = new DataDriverManager(), + proc = self.mock || process, + i, + descJson; + + self.logger.debug('Loading descriptor file: ' + self.testDataPath); + descriptorJsonStr = fs.readFileSync(self.testDataPath, "utf-8"); + try { + descriptorJson = JSON.parse(descriptorJsonStr); + } catch (e) { + self.logger.error('The descriptor ' + self.testDataPath + ' contains invalid JSON'); + proc.exit(1); + } + + self.isDataDriven = descriptorJson[0].dataDriver || (descriptorJson[0].config instanceof Array); - self.logger.debug('Loading descriptor file: ' + this.testDataPath); + // Process data driven descriptors + if (self.isDataDriven) { + + dataDrivenDescriptorArr = dataDriverManager.processDataDriver(self.testDataPath, descriptorJson); + + if (dataDrivenDescriptorArr && dataDrivenDescriptorArr.length > 0) { + + for (i = 0; i < dataDrivenDescriptorArr.length; i += 1) { + + descJson = dataDrivenDescriptorArr[i]; + descriptor = self.getDescriptor(descJson); + descriptorArr.push(descriptor); + } + } + + } else { + descriptor = self.getDescriptor(descriptorJson); + descriptorArr.push(descriptor); + } + return descriptorArr; + +}; + +/** + * + * @param descriptorJson + * @returns {*} Processed descriptor Json + */ +DataProvider.prototype.getDescriptor = function(descriptorJson) { - descriptorJsonStr = fs.readFileSync(this.testDataPath, "utf-8"); - descriptorJson = JSON.parse(descriptorJsonStr); - relativePath = path.dirname(self.testDataPath); - importDescriptor = descriptorJson[0].importDescriptor; + var importDescriptor = descriptorJson[0].importDescriptor, + importManager = new ImportManager(), + cwd = global.workingDirectory || process.cwd(), + contextObj, + baseUrl, + dimensionsJson, + self = this, + descriptor, + relativePath = path.dirname(self.testDataPath); // Importing descriptor if (importDescriptor) { @@ -67,33 +109,66 @@ DataProvider.prototype.getTestData = function () { } // read context into object - contextObj = qs.parse(this.context, ",", ":"); - + contextObj = qs.parse(self.context, ",", ":"); baseUrl = self.config["baseUrl"]; // inject baseUrl into the settings + self.injectBaseUrlFromSettings(descriptorJson, baseUrl); + + // Process extend descriptor + descriptorJson = self.processExtendDescriptor(descriptorJson, cwd, relativePath); + + // merge dimension into descriptor + if (self.dimensions) { + dimensionsJson = self.readAndValidateJSON(self.dimensions); + descriptorJson.unshift(dimensionsJson[0]); + } + + // Apply ycb substitution + descriptor = self.applyYcbSubstitution(descriptorJson, contextObj); + + // Replace params in the descriptor , if user has passed either of replaceParamJSON or defaultParamJSON + if (self.replaceParamJSON || self.defaultParamJSON) { + descriptor = self.getDescriptorWithReplacedParams(descriptor); + } + + // Validate descriptor against the schema + self.validateDescriptor(descriptor, self.config["arrowModuleRoot"] + "config/descriptor-schema.json"); + + return descriptor; +}; + +/** + * Inject baseUrl if passed from command line or specified in config file + */ +DataProvider.prototype.injectBaseUrlFromSettings = function(descriptorJson, baseUrl) { + + var pos; if (baseUrl && baseUrl.length > 0) { for (pos = 0; pos < descriptorJson.length; pos += 1) { if (descriptorJson[pos].settings) { - if (!descriptorJson[pos].config) { descriptorJson[pos].config = {}; } + if (!descriptorJson[pos].config) { + descriptorJson[pos].config = {}; + } descriptorJson[pos].config.baseUrl = baseUrl; } } } - //checking if descriptor is extending another json - if (descriptorJson[0].extends) { - - // Resolve path - descriptorJson[0].extends = path.resolve(cwd, relativePath, descriptorJson[0].extends); +}; - baseJson = JSON.parse(fs.readFileSync(descriptorJson[0].extends)); - descriptorJson = descriptorJson.concat(baseJson); - } +/** + * + * @param descriptorJson + * @param contextObj + * @returns {*} + */ +DataProvider.prototype.applyYcbSubstitution = function(descriptorJson, contextObj) { - // merge dimension into descriptor - dimensionsJson = JSON.parse(fs.readFileSync(this.dimensions, "utf-8")); - descriptorJson.unshift(dimensionsJson[0]); + var descriptor, + match, + self = this, + proc = self.mock || process; try { descriptor = ycb.read(descriptorJson, contextObj, false, false); @@ -108,22 +183,26 @@ DataProvider.prototype.getTestData = function () { } proc.exit(1); } + return descriptor; +}; - // Replace params in the descriptor , if user has passed either of replaceParamJSON or defaultParamJSON - if (this.replaceParamJSON || this.defaultParamJSON) { - descriptor = this.getDescriptorWithReplacedParams(descriptor); - } - - descriptorSchema = JSON.parse(fs.readFileSync(self.config["arrowModuleRoot"] + "config/descriptor-schema.json", "utf-8")); - - report = JSV.createEnvironment().validate(descriptor, descriptorSchema); +/** + * if descriptor is extending another json + * @param descriptorJson + * @param cwd + * @param relativePath + */ +DataProvider.prototype.processExtendDescriptor = function(descriptorJson, cwd, relativePath) { - if (report.errors.length > 0) { - self.logger.fatal("Error : " + self.testDataPath + " failed Schema Test !"); - self.logger.info(report.errors); - proc.exit(1); + //checking if descriptor is extending another json + if (descriptorJson[0]['extends']) { + // Resolve path + descriptorJson[0]['extends'] = path.resolve(cwd, relativePath, descriptorJson[0]['extends']); + var baseJson = JSON.parse(fs.readFileSync(descriptorJson[0]['extends'])); + descriptorJson = descriptorJson.concat(baseJson); } - return descriptor; + return descriptorJson; + }; /** @@ -137,27 +216,41 @@ DataProvider.prototype.readAndValidateJSON = function (param) { json, parsedJson, self = this, - pwd = global.workingDirectory || ''; + pwd = global.workingDirectory || '', + proc = self.mock || process, + isFile = false, + errMsg; if (param) { - if (param.indexOf(".json") > 0) { + + try { + // If file, read Json from file and validate paramPath = path.resolve(pwd, param); json = fs.readFileSync(paramPath, "utf-8"); - } else { + isFile = true; + } catch (e) { + // Not a file, so treat it as json string json = param; } try { parsedJson = JSON.parse(json); } catch (msg) { - self.logger.error(param + " is not a valid JSON"); + + if (isFile) { + errMsg = "The file " + param + " does not contain valid JSON"; + } else { + errMsg = param + " is not a valid JSON"; + } self.logger.error(msg); - process.exit(1); + self.logger.error(errMsg); + + proc.exit(1); } } - return parsedJson; + return parsedJson; }; @@ -227,4 +320,38 @@ DataProvider.prototype.getDescriptorWithReplacedParams = function (descriptor) { }; +/** + * + * @param descriptor + * @param descriptorSchemaPath + */ +DataProvider.prototype.validateDescriptor = function (descriptor, descriptorSchemaPath) { + + var descriptorSchema, + report, + self = this, + proc = self.mock || process; + + try { + descriptorSchema = fs.readFileSync(descriptorSchemaPath, "utf-8"); + descriptorSchema = JSON.parse(descriptorSchema); + + // Add dataDriverKey as a hidden property + descriptorSchema.properties.dataDriverKey = {"type":"string"}; + + } catch (e) { + self.logger.error('Failed to read/parse descriptor schema - error :' + e); + proc.exit(1); + } + + report = JSV.createEnvironment().validate(descriptor, descriptorSchema); + + if (report.errors.length > 0) { + self.logger.fatal("Error : " + self.testDataPath + " failed Schema Test !"); + self.logger.info(report.errors); + proc.exit(1); + } + +}; + module.exports = DataProvider; \ No newline at end of file diff --git a/lib/util/errormanager.js b/lib/util/errormanager.js index 77b919e1..160ab2f4 100644 --- a/lib/util/errormanager.js +++ b/lib/util/errormanager.js @@ -51,7 +51,7 @@ ErrorManager.instance = null; * @param value for placeholders. */ ErrorManager.prototype.error = function () { - var i = 0, args = [], arg = "", message = "", errorCodeJson, errorName, key; + var i = 0, args = [], message = "", errorCodeJson, key; Array.prototype.push.apply(args, arguments); if (typeof args[0] === "string") { message = args[0]; diff --git a/lib/util/fileutil.js b/lib/util/fileutil.js index a9efea14..ba11371f 100644 --- a/lib/util/fileutil.js +++ b/lib/util/fileutil.js @@ -62,22 +62,4 @@ FileUtil.prototype.removeDirectory = function(dirPath, callback) { }; -FileUtil.prototype.deleteFile = function(filePath, callback) { - - try { - - if (existsSync(filePath)) { - fs.unlinkSync(filePath); - callback(); - } else { - callback(); - } - - } catch (e) { - this.logger.info('Error deleting file - ' + filePath + 'Error:' + e); - callback(); - } - -}; - module.exports = FileUtil; \ No newline at end of file diff --git a/lib/util/importmanager.js b/lib/util/importmanager.js index 733e0606..956fc441 100644 --- a/lib/util/importmanager.js +++ b/lib/util/importmanager.js @@ -88,6 +88,12 @@ ImportManager.prototype.processImportDescriptor = function(testDataPath, cwd, gr for (i = 0; i < importDescriptorArr.length; i += 1) { + // testDataPath might full path, and might relatvie + // plan to convert pull path to relative path and avoid path join errors with cwd + if (testDataPath.substr(0, cwd.length) === cwd){ + testDataPath = path.relative(cwd, testDataPath); + } + // Resolve paths importingDescRelPath = path.dirname(testDataPath); @@ -112,7 +118,9 @@ ImportManager.prototype.processImportDescriptor = function(testDataPath, cwd, gr commonLib = importJson.commonlib; // Resolve commonLib - resolvedCommonLib += self.getResolvedCommonLib(commonLib, importedDescPath); + if (commonLib) { + resolvedCommonLib += ((resolvedCommonLib.length > 0) ? "," : "") + self.getResolvedCommonLib(commonLib, importedDescPath); + } // Add tests if (importJson && importJson.dataprovider) { @@ -132,8 +140,12 @@ ImportManager.prototype.processImportDescriptor = function(testDataPath, cwd, gr descriptorJson[0].dataprovider = testObj; - if (resolvedCommonLib) { - descriptorJson[0].commonlib = descriptorJson[0].commonlib + ',' + resolvedCommonLib; + if (resolvedCommonLib) { + if (descriptorJson[0].commonlib) { + descriptorJson[0].commonlib = descriptorJson[0].commonlib + ',' + resolvedCommonLib; + } else { + descriptorJson[0].commonlib = resolvedCommonLib; + } } delete descriptorJson[0]['importDescriptor']; @@ -208,4 +220,4 @@ ImportManager.prototype.getResolvedCommonLib = function(commonLib, relPathDirNam }; -module.exports = ImportManager; \ No newline at end of file +module.exports = ImportManager; diff --git a/lib/util/libmanager.js b/lib/util/libmanager.js index c8591410..23b618b8 100644 --- a/lib/util/libmanager.js +++ b/lib/util/libmanager.js @@ -23,26 +23,27 @@ LibManager.prototype.getAllTest = function (strLibPath, relativePath) { tmpArr, result, i, - j; + j, + lib; this.strLibPath = strLibPath; this.logger.trace("Normalizing libs: " + strLibPath); arrLib = this.strLibPath.split(","); for (i = 0; i < arrLib.length; i += 1) { + lib = arrLib[i].trim(); try { - if (relativePath) { - arrLib[i] = path.resolve(global.workingDirectory, relativePath, arrLib[i]); + lib = path.resolve(global.workingDirectory, relativePath, lib); } - if (fs.statSync(arrLib[i])) { - stat = fs.statSync(arrLib[i]); + if (fs.statSync(lib)) { + stat = fs.statSync(lib); if (stat.isFile()) { - if (-1 !== arrLib[i].indexOf(".js")) { - libs += arrLib[i] + ","; + if (-1 !== lib.indexOf(".js")) { + libs += lib + ","; } else { - this.logger.warn(arrLib[i] + " is not a .js file, ignoring this library !"); + this.logger.warn(lib + " is not a .js file, ignoring this library !"); } } else if (stat.isDirectory()) { - dir = arrLib[i]; + dir = lib; if ("/" === dir.substr(dir.length - 1, dir.length)) { dir = dir.substr(0, dir.length - 1); } @@ -53,21 +54,21 @@ LibManager.prototype.getAllTest = function (strLibPath, relativePath) { } } } else { - this.logger.warn("Unable to read :" + arrLib[i] + ", ignoring this library !"); + this.logger.warn("Unable to read :" + lib + ", ignoring this library !"); } } } catch (e) { // checking if its a framework lib - if (arrLib[i].indexOf(".") === -1) { - result = glob.sync(path.resolve(global.appRoot, "sharelib", "lib") + "/**/" + arrLib[i] + ".js"); + if (lib.indexOf(".") === -1) { + result = glob.sync(path.resolve(global.appRoot, "sharelib", "lib") + "/**/" + lib + ".js"); if (result.length > 0) { stat = fs.statSync(result[0]); if (stat.isFile()) { libs += result[0] + ","; } } else { - this.logger.warn("Unable to read :" + arrLib[i] + ", ignoring this library !"); + this.logger.warn("Unable to read :" + lib + ", ignoring this library !"); } } else { diff --git a/lib/util/mockchildprocess.js b/lib/util/mockchildprocess.js index a9458a3b..6af41fd5 100644 --- a/lib/util/mockchildprocess.js +++ b/lib/util/mockchildprocess.js @@ -42,8 +42,7 @@ 'use strict'; -var util = require("util"), - child_process = require("child_process"), +var child_process = require("child_process"), verbose = true, counter = 0, path = require('path'), diff --git a/lib/util/phantomJsSetup.js b/lib/util/phantomJsSetup.js index 1582a2a5..77f5b1c2 100644 --- a/lib/util/phantomJsSetup.js +++ b/lib/util/phantomJsSetup.js @@ -3,115 +3,160 @@ var child_process = require('child_process'), portchecker = require('../../ext-lib/portchecker'), child, + phantomHost, log4js = require("log4js"), phantomJsLogger = new log4js.getLogger("PhantomJsSetupLogger"), - PhantomJsSetup = module.exports = {}; + http = require("http"), + self; -PhantomJsSetup.waitForPhantomJs = function(childProcess, time, port, cb) { +var PhantomJsSetup = (function() { - var tid, - maxTries = 50, - serverStarted = false, - out, - index, - self = this, - phantomJsStartMsg; + var instance; - // PhantomJs 1.9 : GhostDriver - Main - running on port , PhantomJs 1.8 : Ghost Driver running on port - phantomJsStartMsg = 'running on port ' + port; + function init () { - tid = setInterval(function () { + instance = new Object(); - if (maxTries === 0) { - phantomJsLogger.info('Max Tries Over to start phantomJs..'); - clearInterval(tid); - cb(false); - } - maxTries -= 1; + instance.waitForPhantomJs = function(childProcess, time, port, cb) { - }, time); + var tid, + maxTries = 50, + serverStarted = false, + out, + index, + phantomJsStartMsg; - out = ''; + // PhantomJs 1.9 : GhostDriver - Main - running on port , PhantomJs 1.8 : Ghost Driver running on port + phantomJsStartMsg = 'running on port ' + port; - childProcess.stdout.on('data', function(stdout) { + tid = setInterval(function () { - out = out + stdout; - // No need to callback again ,if server has already started - if (!serverStarted) { + if (maxTries === 0) { + phantomJsLogger.info('Max Tries Over to start phantomJs..'); + clearInterval(tid); + cb(false); + } + maxTries -= 1; - index = out.indexOf(phantomJsStartMsg); - if (index !== -1) { - phantomJsLogger.info("PhantomJs Server started successfully"); - clearInterval(tid); - serverStarted = true; - cb(true); - } - } + }, time); - }); + out = ''; - childProcess.stderr.on('data', function(stderr) { - phantomJsLogger.debug('Error while starting phantomjs:' + stderr); - }); + childProcess.stdout.on('data', function(stdout) { + out = out + stdout; + // No need to callback again ,if server has already started + if (!serverStarted) { -}; + index = out.indexOf(phantomJsStartMsg); + if (index !== -1) { + phantomJsLogger.info("PhantomJs Server started successfully"); + clearInterval(tid); + serverStarted = true; + cb(true); + } + } -PhantomJsSetup.startPhantomJs = function (ignoreSslErrorsPhantomJs, cb) { + }); - var - self = this, - minPort = 10000, - maxPort = 11000, - childProcess = require("child_process"), - args = [], - phantomHost, - retryTime = 400; + childProcess.stderr.on('data', function(stderr) { + phantomJsLogger.error('Error while starting phantomjs:' + stderr); + }); - if (!ignoreSslErrorsPhantomJs) { - ignoreSslErrorsPhantomJs = false; - } - try { + }; - portchecker.getFirstAvailable(minPort, maxPort, "localhost", function (p, host) { - if (p === -1) { - phantomJsLogger.debug('No free ports found for arrow server on ' + host + ' between ' + minPort + ' and ' + maxPort); - } else { - phantomJsLogger.debug('The first free port found for arrow server on ' + host + ' between ' + minPort + ' and ' + maxPort + ' is ' + p); - args.push('--webdriver=' + p); - args.push('--ignore-ssl-errors=' + ignoreSslErrorsPhantomJs); - phantomJsLogger.debug('PhantomJs starting with arguments -' + args); - child = childProcess.spawn('phantomjs', args, {}); + instance.startPhantomJs = function (ignoreSslErrorsPhantomJs, cb) { + var + self = PhantomJsSetup.getInstance(), + minPort = 10000, + maxPort = 11000, + childProcess = require("child_process"), + args = [], + retryTime = 400; - self.waitForPhantomJs(child, retryTime, p, function(running) { + if (!ignoreSslErrorsPhantomJs) { + ignoreSslErrorsPhantomJs = false; + } + + try { - if (running === true) { - phantomHost = 'http://localhost:' + p + "/wd/hub"; - phantomJsLogger.info('PhantomJS up and running on ' + phantomHost); + portchecker.getFirstAvailable(minPort, maxPort, "localhost", function (p, host) { + if (p === -1) { + phantomJsLogger.debug('No free ports found for arrow server on ' + host + ' between ' + minPort + ' and ' + maxPort); } else { - phantomJsLogger.info('Error !! PhantomJS could not start..'); + phantomJsLogger.debug('The first free port found for arrow server on ' + host + ' between ' + minPort + ' and ' + maxPort + ' is ' + p); + args.push('--webdriver=' + p); + args.push('--ignore-ssl-errors=' + ignoreSslErrorsPhantomJs); + phantomJsLogger.debug('PhantomJs starting with arguments -' + args); + child = childProcess.spawn('phantomjs', args, {}); + + self.waitForPhantomJs(child, retryTime, p, function(running) { + + if (running === true) { + phantomHost = 'http://localhost:' + p + "/wd/hub"; + phantomJsLogger.info('PhantomJS up and running on ' + phantomHost); + } else { + phantomJsLogger.info('Error !! PhantomJS could not start..'); + } + cb(phantomHost); + }); } - cb(phantomHost); }); + + } catch (e) { + phantomJsLogger.error('Exception in starting phantomjs :' + e); } - }); + }; - } catch (e) { - phantomJsLogger.debug('Exception in starting phantomjs :' + e); - } -}; + instance.stopPhantomJs = function () { + if (child) { + child.kill(); + phantomJsLogger.info("PhantomJs stopped"); + } + }; + + instance.isPhantomJsRunning = function (cb) { -/** - * stop phantomjs - */ -PhantomJsSetup.stopPhantomJs = function () { + if (phantomHost) { + var phantomUrl = phantomHost + "/sessions"; + phantomJsLogger.debug("PhantomHost::" + phantomUrl); + + http.get(phantomUrl, function(response){ + phantomJsLogger.debug('Status code :' + response.statusCode); + if (response.statusCode === 200) { + phantomJsLogger.debug('PhantomJs is running'); + cb(true); + } else { + phantomJsLogger.debug('PhantomJs is NOT running'); + cb(false); + } + return; + }).on('error', function(e){ + phantomJsLogger.error('Got error on HTTP get for the phantomjs url - ' + phantomUrl + ' : ' + e.message); + cb(false); + }) + } else { + phantomJsLogger.debug('phantomHost is NOT set'); + cb(false); + } + + }; + + }; + + return { + + getInstance: function() { + if (!instance) { + init(); + } + + return instance; + } - if (child) { - child.kill(); - phantomJsLogger.info("PhantomJs stopped"); } -}; +})(); module.exports = PhantomJsSetup; \ No newline at end of file diff --git a/lib/util/reportmanager.js b/lib/util/reportmanager.js index 0f9a57d2..04abab30 100644 --- a/lib/util/reportmanager.js +++ b/lib/util/reportmanager.js @@ -97,7 +97,7 @@ ReportManager.prototype.addTest = function (time, className, name, failureMessag ReportManager.prototype.parseYUIResults = function (testJson, dtName, self, screenShotPaths) { - var l, m, errorRep, + var l, m, yuiUserAgent = testJson.ua, yuiSuiteName = testJson.name, browser = UserAgent.parse(yuiUserAgent).toAgent(), @@ -107,7 +107,9 @@ ReportManager.prototype.parseYUIResults = function (testJson, dtName, self, scre timePerTest, className, testName, - screenShotPathsMsg; + screenShotPathsMsg, + sauceLabsReportMsg, + sauceLabsReportUrl; if (browser === "Other 0.0.0") { browser = "NodeJS"; @@ -130,10 +132,20 @@ ReportManager.prototype.parseYUIResults = function (testJson, dtName, self, scre testName = yuiSuiteName + "::" + yuiTestCaseName + "::" + testJson[l][m].name; if (testJson[l][m].result === "fail") { screenShotPathsMsg = ''; + sauceLabsReportMsg = ''; if (screenShotPaths) { screenShotPathsMsg = self.getScreenShotsMsg(screenShotPaths); } - self.addTest(timePerTest, className, testName, testJson[l][m].message + "." + "\n" + " URL :" + currentUrl + screenShotPathsMsg); + + if (testJson.sauceLabsReportUrl) { + sauceLabsReportUrl = testJson.sauceLabsReportUrl; + sauceLabsReportMsg = '\n\n\nSauce Labs Report : ' + sauceLabsReportUrl; + } + + self.addTest(timePerTest, className, testName, testJson[l][m].message + + "." + "\n" + " URL :" + + currentUrl + sauceLabsReportMsg + screenShotPathsMsg); + } else if (testJson[l][m].result === "pass") { self.addTest(timePerTest, className, testName); } else if (testJson[l][m].result === "ignore") { @@ -158,7 +170,7 @@ ReportManager.prototype.showReportOnConsole = function (result, verbose) { } else { log("Passed ".green + result.name.blue + " on " + browser); } - log((result.passed + " Passed").green + ", " + (result.failed + " Failed ").red + ", " + (result.ignored + " skipped ").grey); + log((result.passed + " Passed").green + ", " + (result.failed + " Failed").red + ", " + (result.ignored + " Skipped ").grey); if (result.failed) { for (k in result) { suite = result[k]; @@ -175,7 +187,7 @@ ReportManager.prototype.showReportOnConsole = function (result, verbose) { lastSuite = suite.name; } msg = test.message.split('\n'); - log(" " + test.name.bold.red + ":" + msg[0]); + log(" " + test.name.bold.red + ": " + msg[0]); for (m = 1; m < msg.length; m = m + 1) { log(" " + msg[m]); } @@ -187,6 +199,12 @@ ReportManager.prototype.showReportOnConsole = function (result, verbose) { } } log(""); + + if (result.sauceLabsReportUrl) { + log("Sauce labs report: " + result.sauceLabsReportUrl); + log(""); + } + }; /** @@ -362,14 +380,18 @@ ReportManager.prototype.writeReports = function () { } - xmlReportName = path.resolve(dirPath, path.basename(this.reportObj.descriptor, '.json') + "-report.xml"); - jsonReportName = path.resolve(dirPath, path.basename(this.reportObj.descriptor, '.json') + "-report.json"); - + var dataDriverKey = ''; + if (this.reportObj.dataDriverKey) { + dataDriverKey = '-' + this.reportObj.dataDriverKey; + } + var reportPath = path.resolve(dirPath,path.basename(this.reportObj.descriptor + dataDriverKey, '.json')); + xmlReportName = reportPath + "-report.xml"; + jsonReportName = reportPath + "-report.json"; if (this.failCount > 0) { - global.failedDescriptors.push({"desc" : this.reportObj.descriptor, "failures" : this.failCount}); + global.failedDescriptors.push({"desc" : this.reportObj.descriptor, "failures" : this.failCount, "dataDriverKey":this.reportObj.dataDriverKey}); } - log(("Test Report Summary for the descriptor::" + this.reportObj.descriptor).bold.magenta.toString()); + log(("Test Report Summary for the descriptor::" + this.reportObj.descriptor + ' ' + dataDriverKey).bold.magenta.toString()); logTestResults(this); @@ -394,9 +416,14 @@ ReportManager.prototype.writeReports = function () { log("\n*************************************************************************************"); log(" List of failed descriptors "); - for (i = 0; i < global.failedDescriptors.length; i += 1) { - log('\nFailed Descriptor Path : ' + global.failedDescriptors[i].desc); + + if (global.failedDescriptors[i].desc && global.failedDescriptors[i].dataDriverKey) { + log("\nFailed Data driven Descriptor Path : " + global.failedDescriptors[i].desc + " - for the data driver item '" + global.failedDescriptors[i].dataDriverKey + "'"); + } else { + log('\nFailed Descriptor Path : ' + global.failedDescriptors[i].desc); + } + log('Total Number of Failed Tests : ' + global.failedDescriptors[i].failures); log("-----------------------------------------------------------------------"); } diff --git a/lib/util/sauceLabsUtil.js b/lib/util/sauceLabsUtil.js new file mode 100644 index 00000000..de9fa3ad --- /dev/null +++ b/lib/util/sauceLabsUtil.js @@ -0,0 +1,44 @@ +/*jslint forin:true sub:true anon:true, sloppy:true, stupid:true nomen:true, node:true continue:true*/ + +/* + * Copyright (c) 2014, Yahoo! Inc. All rights reserved. + * Copyrights licensed under the New BSD License. + * See the accompanying LICENSE file for terms. + */ + +var SauceLabs = require('saucelabs'); +var log4js = require("log4js"); + +function SauceLabsUtil() { + this.logger = log4js.getLogger("SauceLabsUtil"); +} + +/** + * Update sauce labs job status + * @param result + * @param sessionId + * @param sauceUser + * @param sauceKey + * @param callback + */ +SauceLabsUtil.prototype.updateJobStatus = function(result, sessionId, sauceUser, + sauceKey, callback) { + var sauceLabs = new SauceLabs({username: sauceUser, password: sauceKey}), + self = this; + + sauceLabs.updateJob(sessionId, result, function(err) { + if (err) { + callback(new Error('Error updating Sauce pass/fail status: ' + err)); + return; + } + + self.logger.debug('Updated result successfully to SauceLabs for session id - ' + + sessionId); + + callback(null); + return; + }); + +}; + +module.exports = SauceLabsUtil; \ No newline at end of file diff --git a/lib/util/webdrivermanager.js b/lib/util/webdrivermanager.js index f90b1009..50008bc0 100644 --- a/lib/util/webdrivermanager.js +++ b/lib/util/webdrivermanager.js @@ -7,8 +7,7 @@ */ var log4js = require("log4js"); -var fs = require("fs"); -var path = require("path"); + /** * web driver manager diff --git a/nodejs/node.js b/nodejs/node.js index 5b246423..969abe44 100755 --- a/nodejs/node.js +++ b/nodejs/node.js @@ -8,7 +8,8 @@ var fs = require('fs'); var path = require('path'); -var logger = require("log4js").getLogger("runNodejsTest"); +var log4js = require("log4js"); +var logger = log4js.getLogger("runNodejsTest"); var coverage = require('../lib/util/coverage'); ARROW = {}; @@ -35,6 +36,7 @@ var waitForExitTimeout = 1000; var receivedShareData = undefined; var waitForShareDataTimeout = 1000; var waitForShareDataInterval = 100; + process.on('message', function(m) { if (m.shared) { logger.debug("Received shared data."); @@ -49,6 +51,9 @@ var testTimeOut = testSpec.testTimeOut; testTimeOut = typeof testTimeOut === "string" ? parseInt(testTimeOut) : testTimeOut; coverage.configure(testSpec); +// Set logLevel passed from parent process +setLogLevel(testSpec.logLevel); + function getReportStatus() { logger.info("Waiting for the test report"); if ((null === ARROW.testReport) || ARROW.testReport == undefined || (0 === ARROW.testReport.length)) { @@ -139,6 +144,15 @@ function runTest() { } +/** + * set logLevel passed from parent process + * @param logLevel + */ +function setLogLevel(logLevel){ + log4js.setGlobalLogLevel(logLevel); + log4js.restoreConsole(); +} + if (coverageFlag) { coverage.hookRequire(); } diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 9da004e0..9db6fdd9 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,155 +1,374 @@ { "name": "yahoo-arrow", - "version": "0.3.0", + "version": "0.6.14", "dependencies": { + "body-parser": { + "version": "1.12.0", + "from": "body-parser@1.x", + "dependencies": { + "bytes": { + "version": "1.0.0", + "from": "bytes@1.0.0" + }, + "content-type": { + "version": "1.0.1", + "from": "content-type@~1.0.1" + }, + "debug": { + "version": "2.1.2", + "from": "debug@~2.1.1", + "dependencies": { + "ms": { + "version": "0.7.0", + "from": "ms@0.7.0" + } + } + }, + "depd": { + "version": "1.0.0", + "from": "depd@~1.0.0" + }, + "iconv-lite": { + "version": "0.4.7", + "from": "iconv-lite@0.4.7" + }, + "on-finished": { + "version": "2.2.0", + "from": "on-finished@~2.2.0", + "dependencies": { + "ee-first": { + "version": "1.1.0", + "from": "ee-first@1.1.0" + } + } + }, + "qs": { + "version": "2.3.3", + "from": "qs@2.3.3" + }, + "raw-body": { + "version": "1.3.3", + "from": "raw-body@1.3.3" + }, + "type-is": { + "version": "1.6.0", + "from": "type-is@~1.6.0", + "dependencies": { + "media-typer": { + "version": "0.3.0", + "from": "media-typer@0.3.0" + }, + "mime-types": { + "version": "2.0.9", + "from": "mime-types@~2.0.9", + "dependencies": { + "mime-db": { + "version": "1.7.0", + "from": "mime-db@~1.7.0" + } + } + } + } + } + } + }, "glob": { "version": "3.1.11", + "from": "glob@3.1.11", "dependencies": { "minimatch": { - "version": "0.2.12", + "version": "0.2.14", + "from": "minimatch@0.2", "dependencies": { "lru-cache": { - "version": "2.3.0" + "version": "2.5.0", + "from": "lru-cache@2" }, "sigmund": { - "version": "1.0.0" + "version": "1.0.0", + "from": "sigmund@~1.0.0" } } }, "graceful-fs": { - "version": "1.1.14" + "version": "1.1.14", + "from": "graceful-fs@~1.1.2" }, "inherits": { - "version": "1.0.0" + "version": "1.0.0", + "from": "inherits@1" } } }, "nopt": { "version": "2.0.0", + "from": "nopt@2.0.0", "dependencies": { "abbrev": { - "version": "1.0.4" + "version": "1.0.5", + "from": "abbrev@1" + } + } + }, + "cookie-parser": { + "version": "1.3.4", + "from": "cookie-parser@1.x", + "dependencies": { + "cookie": { + "version": "0.1.2", + "from": "cookie@0.1.2" + }, + "cookie-signature": { + "version": "1.0.6", + "from": "cookie-signature@1.0.6" } } }, "colors": { - "version": "0.6.0-1" + "version": "0.6.0-1", + "from": "colors@0.6.0-1" }, "express": { - "version": "3.0.0", + "version": "4.12.2", + "from": "express@4.x", "dependencies": { - "connect": { - "version": "2.6.0", + "accepts": { + "version": "1.2.4", + "from": "accepts@~1.2.4", "dependencies": { - "qs": { - "version": "0.5.1" - }, - "formidable": { - "version": "1.0.11" - }, - "bytes": { - "version": "0.1.0" - }, - "send": { - "version": "0.0.4", + "mime-types": { + "version": "2.0.9", + "from": "mime-types@~2.0.9", "dependencies": { - "mime": { - "version": "1.2.6" + "mime-db": { + "version": "1.7.0", + "from": "mime-db@~1.7.0" } } }, - "pause": { - "version": "0.0.1" + "negotiator": { + "version": "0.5.1", + "from": "negotiator@0.5.1" } } }, - "commander": { - "version": "0.6.1" + "content-disposition": { + "version": "0.5.0", + "from": "content-disposition@0.5.0" }, - "range-parser": { - "version": "0.0.4" + "content-type": { + "version": "1.0.1", + "from": "content-type@~1.0.1" }, - "mkdirp": { - "version": "0.3.3" + "cookie-signature": { + "version": "1.0.6", + "from": "cookie-signature@1.0.6" }, - "cookie": { - "version": "0.0.4" + "debug": { + "version": "2.1.2", + "from": "debug@~2.1.1", + "dependencies": { + "ms": { + "version": "0.7.0", + "from": "ms@0.7.0" + } + } + }, + "depd": { + "version": "1.0.0", + "from": "depd@~1.0.0" + }, + "escape-html": { + "version": "1.0.1", + "from": "escape-html@1.0.1" + }, + "etag": { + "version": "1.5.1", + "from": "etag@~1.5.1", + "dependencies": { + "crc": { + "version": "3.2.1", + "from": "crc@3.2.1" + } + } }, - "crc": { - "version": "0.2.0" + "finalhandler": { + "version": "0.3.3", + "from": "finalhandler@0.3.3" }, "fresh": { - "version": "0.1.0" + "version": "0.2.4", + "from": "fresh@0.2.4" + }, + "merge-descriptors": { + "version": "1.0.0", + "from": "merge-descriptors@1.0.0" }, "methods": { - "version": "0.0.1" + "version": "1.1.1", + "from": "methods@~1.1.1" + }, + "on-finished": { + "version": "2.2.0", + "from": "on-finished@~2.2.0", + "dependencies": { + "ee-first": { + "version": "1.1.0", + "from": "ee-first@1.1.0" + } + } + }, + "parseurl": { + "version": "1.3.0", + "from": "parseurl@~1.3.0" + }, + "path-to-regexp": { + "version": "0.1.3", + "from": "path-to-regexp@0.1.3" + }, + "proxy-addr": { + "version": "1.0.6", + "from": "proxy-addr@~1.0.6", + "dependencies": { + "forwarded": { + "version": "0.1.0", + "from": "forwarded@~0.1.0" + }, + "ipaddr.js": { + "version": "0.1.8", + "from": "ipaddr.js@0.1.8" + } + } + }, + "qs": { + "version": "2.3.3", + "from": "qs@2.3.3" + }, + "range-parser": { + "version": "1.0.2", + "from": "range-parser@~1.0.2" }, "send": { - "version": "0.1.0", + "version": "0.12.1", + "from": "send@0.12.1", "dependencies": { + "destroy": { + "version": "1.0.3", + "from": "destroy@1.0.3" + }, "mime": { - "version": "1.2.6" + "version": "1.3.4", + "from": "mime@1.3.4" + }, + "ms": { + "version": "0.7.0", + "from": "ms@0.7.0" } } }, - "debug": { - "version": "0.7.2" + "serve-static": { + "version": "1.9.1", + "from": "serve-static@~1.9.1" + }, + "type-is": { + "version": "1.6.0", + "from": "type-is@~1.6.0", + "dependencies": { + "media-typer": { + "version": "0.3.0", + "from": "media-typer@0.3.0" + }, + "mime-types": { + "version": "2.0.9", + "from": "mime-types@~2.0.9", + "dependencies": { + "mime-db": { + "version": "1.7.0", + "from": "mime-db@~1.7.0" + } + } + } + } + }, + "vary": { + "version": "1.0.0", + "from": "vary@~1.0.0" + }, + "cookie": { + "version": "0.1.2", + "from": "cookie@0.1.2" + }, + "utils-merge": { + "version": "1.0.0", + "from": "utils-merge@1.0.0" } } }, "yui": { "version": "3.8.0", + "from": "yui@3.8.0", "dependencies": { "request": { - "version": "2.9.202" + "version": "2.9.202", + "from": "request@2.9.202" } } }, "JSV": { - "version": "4.0.2" + "version": "4.0.2", + "from": "JSV@4.0.2" }, "log4js": { "version": "0.5.1", + "from": "log4js@0.5.1", "dependencies": { "async": { - "version": "0.1.15" + "version": "0.1.15", + "from": "async@0.1.15" } } }, - "clone": { - "version": "0.1.0" - }, - "useragent": { + "useragent": { "version": "1.1.0", + "from": "useragent@1.1.0", "dependencies": { "yamlparser": { - "version": "0.0.2" + "version": "0.0.2", + "from": "yamlparser@0.0.2" }, "request": { - "version": "2.9.202" + "version": "2.9.202", + "from": "request@2.9.202" }, "semver": { - "version": "1.0.14" + "version": "1.0.14", + "from": "semver@1.0.14" } } }, "istanbul": { "version": "0.1.25", + "from": "istanbul@0.1.25", "dependencies": { "esprima": { - "version": "1.0.3" + "version": "1.0.4", + "from": "esprima@1.0.x" }, "escodegen": { - "version": "0.0.23", + "version": "0.0.28", + "from": "escodegen@0.0.x", "dependencies": { "estraverse": { - "version": "0.0.4" + "version": "1.3.2", + "from": "estraverse@~1.3.0" }, "source-map": { - "version": "0.1.23", + "version": "0.4.1", + "from": "source-map@>= 0.1.2", "dependencies": { "amdefine": { - "version": "0.0.5" + "version": "0.1.0", + "from": "amdefine@>=0.0.4" } } } @@ -157,21 +376,27 @@ }, "handlebars": { "version": "1.0.12", + "from": "handlebars@1.0.x", "dependencies": { "optimist": { - "version": "0.3.7" + "version": "0.3.7", + "from": "optimist@~0.3" }, "uglify-js": { "version": "2.3.6", + "from": "uglify-js@~2.3", "dependencies": { "async": { - "version": "0.2.9" + "version": "0.2.10", + "from": "async@~0.2.6" }, "source-map": { - "version": "0.1.23", + "version": "0.1.43", + "from": "source-map@~0.1.7", "dependencies": { "amdefine": { - "version": "0.0.5" + "version": "0.1.0", + "from": "amdefine@>=0.0.4" } } } @@ -181,172 +406,273 @@ }, "fileset": { "version": "0.1.5", + "from": "fileset@0.1.x", "dependencies": { "minimatch": { - "version": "0.2.12", + "version": "0.4.0", + "from": "minimatch@0.x", "dependencies": { "lru-cache": { - "version": "2.3.0" + "version": "2.5.0", + "from": "lru-cache@2" }, "sigmund": { - "version": "1.0.0" + "version": "1.0.0", + "from": "sigmund@~1.0.0" } } } } }, "which": { - "version": "1.0.5" + "version": "1.0.9", + "from": "which@1.0.x" }, "async": { - "version": "0.1.22" + "version": "0.1.22", + "from": "async@0.1.x" }, "abbrev": { - "version": "1.0.4" + "version": "1.0.5", + "from": "abbrev@1.0.x" }, "wordwrap": { - "version": "0.0.2" + "version": "0.0.2", + "from": "wordwrap@0.0.x" } } }, "uglify-js": { - "version": "1.3.4" + "version": "1.3.4", + "from": "uglify-js@1.3.4" }, "xml-writer": { - "version": "1.2.3" + "version": "1.2.3", + "from": "xml-writer@1.2.3" }, "ycb": { - "version": "1.0.5" + "version": "1.0.5", + "from": "ycb@1.0.5" }, "async": { - "version": "0.2.9" + "version": "0.2.10", + "from": "async@~0.2.5" }, "xml2js": { "version": "0.1.14", + "from": "xml2js@0.1.14", "dependencies": { "sax": { - "version": "0.5.4" + "version": "0.6.1", + "from": "sax@>=0.1.1" } } }, "mkdirp": { - "version": "0.3.5" + "version": "0.3.5", + "from": "mkdirp@0.3.5" }, "selenium-webdriver": { - "version": "2.39.0" + "version": "2.39.0", + "from": "selenium-webdriver@2.39.0" + }, + "underscore": { + "version": "1.6.0", + "from": "underscore@1.6.0" + }, + "clone": { + "version": "0.1.11", + "from": "clone@0.1.11" + }, + "saucelabs": { + "version": "0.1.1", + "from": "saucelabs@0.1.1" }, "mocha": { - "version": "1.7.4", + "version": "1.18.2", + "from": "mocha@~1.18.2", "dependencies": { "commander": { - "version": "0.6.1" + "version": "2.0.0", + "from": "commander@2.0.0" }, "growl": { - "version": "1.6.1" + "version": "1.7.0", + "from": "growl@1.7.x" }, "jade": { "version": "0.26.3", + "from": "jade@0.26.3", "dependencies": { + "commander": { + "version": "0.6.1", + "from": "commander@0.6.1" + }, "mkdirp": { - "version": "0.3.0" + "version": "0.3.0", + "from": "mkdirp@0.3.0" } } }, "diff": { - "version": "1.0.2" + "version": "1.0.7", + "from": "diff@1.0.7" }, "debug": { - "version": "0.7.2" - }, - "mkdirp": { - "version": "0.3.3" + "version": "2.1.2", + "from": "debug@*", + "dependencies": { + "ms": { + "version": "0.7.0", + "from": "ms@0.7.0" + } + } }, - "ms": { - "version": "0.3.0" + "glob": { + "version": "3.2.3", + "from": "glob@3.2.3", + "dependencies": { + "minimatch": { + "version": "0.2.14", + "from": "minimatch@~0.2.11", + "dependencies": { + "lru-cache": { + "version": "2.5.0", + "from": "lru-cache@2" + }, + "sigmund": { + "version": "1.0.0", + "from": "sigmund@~1.0.0" + } + } + }, + "graceful-fs": { + "version": "2.0.3", + "from": "graceful-fs@~2.0.0" + }, + "inherits": { + "version": "2.0.1", + "from": "inherits@2" + } + } } } }, "jasmine-node": { "version": "1.4.0", + "from": "jasmine-node@1.4.0", "dependencies": { "coffee-script": { - "version": "1.6.3" + "version": "1.9.1", + "from": "coffee-script@>=1.0.1" }, "jasmine-reporters": { - "version": "0.2.1" + "version": "2.0.4", + "from": "jasmine-reporters@>=0.2.0" }, "requirejs": { - "version": "2.1.6" + "version": "2.1.16", + "from": "requirejs@>=0.27.1" }, "walkdir": { - "version": "0.0.7" - }, - "underscore": { - "version": "1.4.4" + "version": "0.0.7", + "from": "walkdir@>= 0.0.1" }, "gaze": { "version": "0.3.4", + "from": "gaze@~0.3.2", "dependencies": { "minimatch": { - "version": "0.2.12", + "version": "0.2.14", + "from": "minimatch@~0.2.9", "dependencies": { "lru-cache": { - "version": "2.3.0" + "version": "2.5.0", + "from": "lru-cache@2" }, "sigmund": { - "version": "1.0.0" + "version": "1.0.0", + "from": "sigmund@~1.0.0" } } }, "fileset": { - "version": "0.1.5" + "version": "0.1.5", + "from": "fileset@~0.1.5" } } } } }, "qunitjs": { - "version": "1.11.0" + "version": "1.11.0", + "from": "qunitjs@1.11.0" }, "chai": { - "version": "1.5.0" + "version": "1.5.0", + "from": "chai@1.5.0" }, "oauth": { - "version": "0.9.8" + "version": "0.9.8", + "from": "oauth@0.9.8" }, "cheerio": { "version": "0.9.2", + "from": "cheerio@0.9.2", "dependencies": { "htmlparser2": { "version": "2.6.0", + "from": "htmlparser2@2.x", "dependencies": { "domhandler": { - "version": "2.0.3" + "version": "2.0.3", + "from": "domhandler@2.0" }, "domutils": { - "version": "1.0.1" + "version": "1.0.1", + "from": "domutils@1.0" }, "domelementtype": { - "version": "1.1.1" + "version": "1.3.0", + "from": "domelementtype@1" } } }, - "underscore": { - "version": "1.4.4" - }, "entities": { - "version": "0.3.0" + "version": "0.5.0", + "from": "entities@0.x" } } }, "cheerio-select": { "version": "0.0.3", + "from": "cheerio-select@0.0.3", "dependencies": { "CSSselect": { - "version": "0.3.1", + "version": "0.7.0", + "from": "CSSselect@0.x", "dependencies": { "CSSwhat": { - "version": "0.2.0" + "version": "0.4.7", + "from": "CSSwhat@0.4" + }, + "domutils": { + "version": "1.4.3", + "from": "domutils@1.4", + "dependencies": { + "domelementtype": { + "version": "1.3.0", + "from": "domelementtype@1" + } + } + }, + "boolbase": { + "version": "1.0.0", + "from": "boolbase@~1.0.0" + }, + "nth-check": { + "version": "1.0.0", + "from": "nth-check@~1.0.0" } } } diff --git a/package.json b/package.json index b2f704ee..47fc1e1c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "yahoo-arrow", "description": "FrontEnd Testing Framework", - "version": "0.4.3", + "version": "0.6.16", "homepage": "https://github.com/yahoo/arrow", "repository": { "type": "git", @@ -23,16 +23,16 @@ "component": "Arrow" } }, - "author": "Pranav Verma ", + "author": "Pranav V", "contributors": [ - "Sushant Kumar ", - "Ivan Alonso ", - "Payal Shah ", - "Pranav Parikh ", - "Jintao Qiao ", - "Ji Liang ", - "Jun Wang ", - "Ares Huang " + "Sushant K", + "Ivan A", + "Payal S", + "Pranav P", + "Jintao Q", + "Ji L", + "Jun W", + "Ares H" ], "bin": { "arrow": "./index.js", @@ -41,14 +41,15 @@ }, "engines": [ "node >=0.6" ], "dependencies": { + "body-parser": "1.x", "glob": "3.1.11", "nopt": "2.0.0", + "cookie-parser": "1.x", "colors": "0.6.0-1", - "express": "3.0.0", + "express": "4.x", "yui": "3.8.0", "JSV": "4.0.2", "log4js": "0.5.1", - "clone": "0.1.0", "useragent": "1.1.0", "istanbul": "0.1.25", "uglify-js": "1.3.4", @@ -57,10 +58,13 @@ "async": "~0.2.5", "xml2js": "0.1.14", "mkdirp": "0.3.5", - "selenium-webdriver": "2.39.0" + "selenium-webdriver": "2.39.0", + "underscore": "1.6.0", + "clone":"0.1.11", + "saucelabs": "0.1.1" }, "optionalDependencies": { - "mocha": "1.7.4", + "mocha": "~1.18.2", "jasmine-node": "1.4.0", "qunitjs": "1.11.0", "chai": "1.5.0", diff --git a/tests/functional/arrow_commands.sh b/tests/functional/arrow_commands.sh index 1f55130a..3f20658e 100755 --- a/tests/functional/arrow_commands.sh +++ b/tests/functional/arrow_commands.sh @@ -396,4 +396,15 @@ if [ $? != 0 ]; then echo "RESULT: $RESULT" } fi -echo "===== Arrow test done! =====" \ No newline at end of file +let "CNT=$CNT+1" # TEST 33 +echo "TEST$CNT: window size test" +CMD=`$ARROWCI ./data/arrow_test/window_size_test/window_size_test.json | tail $TAILCOUNT | head $HEADCOUNT ` +echo_and_save $CNT "$CMD" +if [ $? != 0 ]; then +{ + echo "ERROR!" + echo "CMD: "$CMD"" + echo "RESULT: $RESULT" +} fi + +echo "===== Arrow test done! =====" diff --git a/tests/functional/data/arrow_test/window_size_test/test-browser-size.js b/tests/functional/data/arrow_test/window_size_test/test-browser-size.js new file mode 100644 index 00000000..5c09dae9 --- /dev/null +++ b/tests/functional/data/arrow_test/window_size_test/test-browser-size.js @@ -0,0 +1,16 @@ +YUI().use('test', function (Y) { + + var suite = new Y.Test.Suite("Browser size test"); + suite.add(new Y.Test.Case({ + + "test browser size equals parameter": function() { + var expectedSize = this.testParams['windowSize']; + + Y.Assert.areEqual(parseInt(expectedSize.width, 10), window.outerWidth); + Y.Assert.areEqual(parseInt(expectedSize.height, 10), window.outerHeight); + } + + })); + + Y.Test.Runner.add(suite); +}); diff --git a/tests/functional/data/arrow_test/window_size_test/test_window_size_descriptor.json b/tests/functional/data/arrow_test/window_size_test/test_window_size_descriptor.json new file mode 100755 index 00000000..f4aad6f8 --- /dev/null +++ b/tests/functional/data/arrow_test/window_size_test/test_window_size_descriptor.json @@ -0,0 +1,28 @@ +[ + { + "settings": [ "master" ], + "name" : "descriptor", + "config": { + "baseUrl": "http://login.yahoo.com" + }, + + "dataprovider" : { + + "Set browser size" : { + "group" : "func", + "browser":"firefox", + "params" :{ + "page": "$$config.baseUrl$$", + "test": "test-browser-size.js", + "windowSize": { + "width": "512", + "height": 512 + } + } + } + } + }, + { + "settings": [ "environment:development" ] + } +] diff --git a/tests/unit/lib/controller/default-tests.js b/tests/unit/lib/controller/default-tests.js index b46e35cf..8f52fefc 100644 --- a/tests/unit/lib/controller/default-tests.js +++ b/tests/unit/lib/controller/default-tests.js @@ -81,7 +81,6 @@ YUI.add('default-tests', function (Y, NAME) { var driver = new StubDriver(), dc, testExecuted = false, - actionExecuted = false, navExecuted = false; dc = new DefaultController({}, {}, driver); @@ -93,10 +92,6 @@ YUI.add('default-tests', function (Y, NAME) { dc.execute(function() { testExecuted = true; }); - dc = new DefaultController({}, {action: 'action.js'}, driver); - dc.execute(function() { - actionExecuted = true; - }); dc = new DefaultController({}, {page: 'test.html'}, driver); dc.execute(function (errMsg) { console.log(errMsg); @@ -110,9 +105,48 @@ YUI.add('default-tests', function (Y, NAME) { }); A.isTrue(testExecuted, "test should be executed"); - A.isTrue(actionExecuted, "action should be executed"); A.isTrue(navExecuted, "nav should be executed"); + }, + + + 'test descriptorSharedParams': function () { + + var driver = new StubDriver(), + arrow = new StubArrow(), + dc, + scenario, + executed = false, + controllers, + testParams = {}; + + Arrow.instance = arrow; + scenario = [ + { + page: 'test.html' + }, + { + controller: 'controller.js' + } + ]; + testParams.scenario = scenario; + testParams.descriptorSharedParams = {}; + testParams.descriptorSharedParams.a = "A"; + testParams.descriptorSharedParams.b = "B"; + + dc = new DefaultController({}, testParams, driver); + + dc.execute(function (errMsg) { + executed = true; + A.isTrue(!errMsg, 'Should have executed scenario'); + }); + + A.isTrue(executed, 'Scenario should be executed'); + controllers = arrow.controllers; + A.areEqual(controllers[0].params.page, 'test.html', 'First atom should have a page'); + A.areEqual(controllers[1].controller, 'controller.js', 'Second atom should have a controller'); } + + })); Y.Test.Runner.add(suite); diff --git a/tests/unit/lib/driver/config/action.js b/tests/unit/lib/driver/config/action.js deleted file mode 100644 index 4b1e3c8e..00000000 --- a/tests/unit/lib/driver/config/action.js +++ /dev/null @@ -1 +0,0 @@ -actionJs \ No newline at end of file diff --git a/tests/unit/lib/driver/selenium-tests.js b/tests/unit/lib/driver/selenium-tests.js index 63875953..b1a372ef 100644 --- a/tests/unit/lib/driver/selenium-tests.js +++ b/tests/unit/lib/driver/selenium-tests.js @@ -150,12 +150,16 @@ YUI.add('selenium-tests', function (Y, NAME) { 'test navigation': function () { var driver, config, - actions; + actions, + params; config = {browser: 'mybrowser', seleniumHost: 'http://wdhub'}; driver = new DriverClass(config, {}); + params = { + page: 'http://mypage' + }; driver.start(function (errMsg) { - driver.navigate('http://mypage', function () { + driver.navigate(params, function () { driver.stop(function (errMsg) { }); }); @@ -168,12 +172,16 @@ YUI.add('selenium-tests', function (Y, NAME) { 'test navigation invalid page': function () { var driver, config, - actions; + actions, + params; config = {browser: 'mybrowser', seleniumHost: 'wdhub'}; driver = new DriverClass(config, {}); + params = { + page: 'http://mypage' + }; driver.start(function (errMsg) { - driver.navigate('http://mypage', function () { + driver.navigate(params, function () { driver.stop(function (errMsg) { }); }); @@ -187,12 +195,16 @@ YUI.add('selenium-tests', function (Y, NAME) { 'test navigation arrow server not running': function () { var driver, config, - actions; + actions, + params; config = {browser: 'mybrowser', seleniumHost: 'wdhub'}; driver = new DriverClass(config, {}); + params = { + page: 'mypage' + }; driver.start(function (errMsg) { - driver.navigate('mypage', function () { + driver.navigate(params, function () { driver.stop(function (errMsg) { }); }); @@ -245,6 +257,72 @@ YUI.add('selenium-tests', function (Y, NAME) { }); }, + 'test execute with page load w/ sauceLabs': function () { + var self = this, + driver, + config = { + browser: 'mybrowser', + seleniumHost: 'http://wdhub', + coverage: true, + isSauceLabs: true + }, + executed = false, + wdMock = require(arrowRoot + '/tests/unit/stub/webdriver'); + + wdMock.WebDriver.prototype.getCapabilities = function (cb) { + var self = this; + return { + then: function (cb) { + var Capabilities = function () { + }; + + Capabilities.prototype.set = function (caps) { + self.caps = caps; + }; + + Capabilities.prototype.get = function (key) { + var val; + if (self.caps.hasOwnProperty(key)) { + val = self.caps[key]; + } + return val; + + }; + + self.capabilities = new Capabilities(); + self.capabilities.set(self.caps); + self.capabilities.caps_ = {}; + self.capabilities.caps_['webdriver.remote.sessionid'] = + 'sauceSessionId'; + cb(self.capabilities); + + } + }; + }; + + mockery.registerMock('../util/wd-wrapper', wdMock); + mockery.enable({ useCleanCache: true }); + + driver = new DriverClass(config, {}); + driver.createDriverJs = function (params, cb) { + cb(null, 'driverjs'); + }; + + function validate() { + var actions = driver.getWebDriver()._actions; + A.isTrue(executed, 'Should have successfully executed test'); + A.areEqual(actions[0].value, 'http://page', 'Should have navigated before test'); + } + + driver.start(function (errMsg) { + var webdriver = driver.getWebDriver(); + webdriver.scriptResults['return ARROW.testReport;'] = '{"name": "functest", "failed": 0, "passed": 0}'; + driver.executeTest({}, {page: 'http://page', test: 'test.js', customController: false}, function (errMsg) { + executed = !errMsg; + validate(); + }); + }); + }, 'test execute with no page load': function () { var self = this, @@ -299,67 +377,6 @@ YUI.add('selenium-tests', function (Y, NAME) { }); }, - - 'test action': function () { - var self = this, - driver, - config = {browser: 'mybrowser', seleniumHost: 'http://wdhub'}, - executed = false; - - function createDriverJs(params, cb) { - cb(null, 'driverjs'); - } - - function validate() { - var actions = driver.getWebDriver()._actions; - A.isTrue(executed, 'Should have successfully executed action'); - A.areEqual(actions[0].value, 'http://page', 'Should have navigated before test'); - } - - driver = new DriverClass(config, {}); - driver.createDriverJs = createDriverJs; - driver.start(function (errMsg) { - var webdriver = driver.getWebDriver(); - webdriver.scriptResults['return ARROW.actionReport;'] = '{}'; - - driver.executeAction({}, {page: 'http://page', action: 'action.js'}, function (errMsg) { - executed = !errMsg; - validate(); - }); - }); - }, - - - 'test action error': function () { - var self = this, - driver, - config = {browser: 'mybrowser', seleniumHost: 'http://wdhub'}, - executed = false; - - function createDriverJs(params, cb) { - cb(null, 'driverjs'); - } - - function validate() { - var actions = driver.getWebDriver()._actions; - A.isTrue(executed, 'Should have successfully executed action'); - } - - driver = new DriverClass(config, {}); - driver.createDriverJs = createDriverJs; -// driver.maxAttempt = 1;//Added for test - driver.start(function (errMsg) { - var webdriver = driver.getWebDriver(); - webdriver.scriptResults['return ARROW.actionReport;'] = '{"error": "action error"}'; - - driver.executeAction({}, {action: 'action.js'}, function (errMsg) { - executed = !!errMsg; // error must not be empty - validate(); - }); - }); - }, - - 'test getArrowServerBase': function () { var self = this, driver, @@ -387,9 +404,8 @@ YUI.add('selenium-tests', function (Y, NAME) { 'test createDriverJs ': function () { var self = this, testRunnerJs = arrowRoot + '/tests/unit/lib/driver/config/testRunner.js', - libJs = arrowRoot + '/tests/unit/lib/driver/config/lib.js', + libJs = arrowRoot + '/tests/unit/lib/driver/config/lib.js' + ' , ' + arrowRoot + '/tests/unit/lib/driver/config/lib.js', seedJs = arrowRoot + '/tests/unit/lib/driver/config/seed.js', - actionJs = arrowRoot + '/tests/unit/lib/driver/config/action.js', testHtml = arrowRoot + '/tests/unit/lib/driver/config/test.html', config = { arrowModuleRoot: arrowRoot, @@ -414,20 +430,20 @@ YUI.add('selenium-tests', function (Y, NAME) { }; driver = new DriverClass(config, {}); driver.createDriverJs({"test": testRunnerJs, - "lib": "," + libJs, "action": actionJs}, function (e) { + "lib": "," + libJs}, function (e) { A.areEqual(null, e, "There should be no error"); }); // Without test driver = new DriverClass(config, {}); - driver.createDriverJs({ "lib": "," + libJs, "action": actionJs}, function (e) { - A.areEqual(null, e, "There should be no error"); + driver.createDriverJs({ "lib": "," + libJs}, function (e) { + A.areEqual("The test js must be specified", e, "Message should be - The test js must be specified"); }); // with html test driver = new DriverClass(config, {}); driver.createDriverJs({"test": testHtml, - "lib": "," + libJs, "action": actionJs}, function (e) { + "lib": "," + libJs}, function (e) { A.areEqual(null, e, "There should be no error"); }); @@ -438,7 +454,6 @@ YUI.add('selenium-tests', function (Y, NAME) { testRunnerJs = arrowRoot + '/tests/unit/lib/driver/config/testRunner.js', libJs = arrowRoot + '/tests/unit/lib/driver/config/libs/lib-one.js,' + arrowRoot + '/tests/unit/lib/driver/config/libs/lib-two.js', seedJs = arrowRoot + '/tests/unit/lib/driver/config/seed.js', - actionJs = arrowRoot + '/tests/unit/lib/driver/config/action.js', testHtml = arrowRoot + '/tests/unit/lib/driver/config/test.html', config = { arrowModuleRoot: arrowRoot, @@ -476,7 +491,6 @@ YUI.add('selenium-tests', function (Y, NAME) { testRunnerJs = arrowRoot + '/tests/unit/lib/driver/config/testRunner.js', libJs = arrowRoot + '/tests/unit/lib/driver/config/libs/lib-one.js,' + arrowRoot + '/tests/unit/lib/driver/config/libs/lib-two.js', seedJs = arrowRoot + '/tests/unit/lib/driver/config/seed.js', - actionJs = arrowRoot + '/tests/unit/lib/driver/config/action.js', testHtml = arrowRoot + '/tests/unit/lib/driver/config/test.html', config = { arrowModuleRoot: arrowRoot, @@ -515,7 +529,6 @@ YUI.add('selenium-tests', function (Y, NAME) { testRunnerJs = arrowRoot + '/tests/unit/lib/driver/config/testRunner.js', libJs = arrowRoot + '/tests/unit/lib/driver/config/libs/lib-one.js,' + arrowRoot + '/tests/unit/lib/driver/config/libs/lib-two.js', seedJs = arrowRoot + '/tests/unit/lib/driver/config/seed.js', - actionJs = arrowRoot + '/tests/unit/lib/driver/config/action.js', testHtml = arrowRoot + '/tests/unit/lib/driver/config/test.html', config = { arrowModuleRoot: arrowRoot, diff --git a/tests/unit/lib/proxy/proxymanager-tests.js b/tests/unit/lib/proxy/proxymanager-tests.js index 76c1b717..44c4ba8c 100644 --- a/tests/unit/lib/proxy/proxymanager-tests.js +++ b/tests/unit/lib/proxy/proxymanager-tests.js @@ -396,19 +396,19 @@ YUI.add('proxymanager-tests', function (Y, NAME) { var proxyManager = new ProxyManager(null, {}), fs = require("fs"), - proxyFileData, timestamp = new Date().getTime(), proxyLogfile = "proxy_" + timestamp + ".log", proxyMsg = "This is proxy log" + timestamp, data; - proxyManager.fileName = proxyLogfile; - + proxyManager.proxyLogFile = proxyLogfile; + console.log('\n\nProxy Logfile::' + proxyManager.proxyLogFile); proxyManager.writeLog(proxyMsg); - - data = fs.readFileSync(proxyManager.fileName, 'utf8'); + console.log('Written'); + data = fs.readFileSync(proxyManager.proxyLogFile, 'utf8'); + console.log('data' + data); A.areEqual(proxyMsg + '\n', data, 'Proxy logs doesn\'t match - expected :' + proxyMsg + '\n' + ' , got this:' + data); - fs.unlinkSync(proxyManager.fileName); + fs.unlinkSync(proxyManager.proxyLogFile); } diff --git a/tests/unit/lib/session/importDescriptor/importDescriptorWithTestLib.json b/tests/unit/lib/session/importDescriptor/importDescriptorWithTestLib.json new file mode 100644 index 00000000..e316ce15 --- /dev/null +++ b/tests/unit/lib/session/importDescriptor/importDescriptorWithTestLib.json @@ -0,0 +1,37 @@ +[ + { + "settings":[ "master" ], + + "name":"controllers", + + "commonlib" : "./imported-test-lib-1.js,./imported-test-lib-2.js", + + "config":{ + "baseUrl":"http://finance.yahoo.com" + }, + + "dataprovider":{ + + "imported test 1":{ + "group":"func", + "params":{ + "page":"$$config.baseUrl$$", + "test":"test.js", + "lib": "../testdata/lib/test-imported-lib.js" + } + }, + + "imported test 2":{ + "group":"smoke", + "params":{ + "page":"$$config.baseUrl$$", + "test":"test.js" + } + } + + } + }, + { + "settings":[ "environment:development" ] + } +] diff --git a/tests/unit/lib/session/sessionfactory-tests.js b/tests/unit/lib/session/sessionfactory-tests.js index f3782b00..c11728a7 100644 --- a/tests/unit/lib/session/sessionfactory-tests.js +++ b/tests/unit/lib/session/sessionfactory-tests.js @@ -194,6 +194,23 @@ YUI.add('sessionfactory-tests', function (Y) { } })); + + suite.add(new Y.Test.Case({ + + name : "Call getFactoryTests with data driven descriptor - verify descriptor name contains key", + + testGetFactoryTestVerifyDescriptorNameContainsKey: function() { + + var ss = new SessionFactory({"dimensions" : arrowRoot + "/config/dimensions.json", "arrowModuleRoot" : arrowRoot + "/", "arrDescriptor" : [__dirname + "/testdata/datadriven-descriptor.json"]},{}), + t, + t = ss.getFactoryTests(); + A.areEqual(2 , t.length, "2 test objects should be returned"); + + A.isTrue(Y.JSON.stringify(t[0].qualifiedDescriptorPath).indexOf('- finance') > 0, "QualifiedDescriptorPath shall contain the data driver key - finance"); + A.isTrue(Y.JSON.stringify(t[1].qualifiedDescriptorPath).indexOf('- yahoo') > 0, "QualifiedDescriptorPath shall contain the data driver key - yahoo"); + } + })); + suite.add(new Y.Test.Case({ name : "Call getFactoryTests with valid descriptor path and matching testName", @@ -287,6 +304,123 @@ YUI.add('sessionfactory-tests', function (Y) { // } // })); + suite.add(new Y.Test.Case({ + + name : "Call getFactoryTests with descriptor shared params", + + testGetFactoryTestWithDescriptorSharedParams: function() { + var ss = new SessionFactory({"dimensions" : arrowRoot + "/config/dimensions.json", "arrowModuleRoot" : arrowRoot + "/", "arrDescriptor": [__dirname + "/testdata/test_descriptor_shared_params.json"]}, + {}), + t; + t = ss.getFactoryTests(); + A.areEqual(1, t.length, "There should be 1 test object"); + + A.areEqual("Yahoo", t[0].params.descriptorSharedParams['yhooquote'], "DescriptorSharedParams - YHOO Quote doesn't match"); + A.areEqual("Apple", t[0].params.descriptorSharedParams['applequote'], "DescriptorSharedParams - AAPL Quote doesn't match"); + + } + })); + + + suite.add(new Y.Test.Case({ + + name : "Exit code failure test", + + testExitFailureTrue: function() { + + var reportObj = + {"reportFolder":"arrow-target","arrTestSessions":[{"logger":{"category":"TestSession","_events":{}},"args":{"config":{},"params":{"lib":"myDirarrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDirarrow/config/config.js","test":"demo/test-greeter.js","page":"myDirarrow/lib/client/testHost.html","customController":false},"testName":"Default","driver":"nodejs","browser":""},"config":{"seleniumHost":"http://localhost:4444/wd/hub","phantomHost":"http://localhost:4445/wd/hub","context":"","defaultAppHost":"","logLevel":"INFO","browser":"firefox","parallel":false,"baseUrl":"","arrowModuleRoot":"myDirarrow/","dimensions":"myDirarrow/config/dimensions.json","defaultTestHost":"myDirarrow/lib/client/testHost.html","defaultAppSeed":"//cdnjs.cloudflare.com/ajax/libs/yui/3.15.0/yui-min.js","autolib":"myDirarrow/lib/common","useYUISandbox":false,"sandboxYUIVersion":"3.8.0","yuiSandboxRuntime":"myDirarrow/lib/client/yui-test-runtime.js","engine":"yui","engineConfig":"","testSeed":"myDirarrow/lib/client/yuitest-seed.js","testRunner":"myDirarrow/lib/client/yuitest-runner.js","shareLibPath":["myDirarrow/sharelib","./common"],"scanShareLibPrefix":[],"scanShareLibRecursive":true,"enableShareLibYUILoader":false,"descriptorName":"test_descriptor.json","minPort":10000,"maxPort":11000,"coverage":false,"coverageExclude":"","exitCode":true,"retryCount":0,"keepIstanbulCoverageJson":false,"color":true,"report":true,"testTimeOut":30000,"ignoreSslErrorsPhantomJs":true,"startPhantomJs":false,"startArrowServer":false,"lib":"demo/greeter.js","artifactsUrl":""},"driverName":"nodejs","testConfig":{},"retryCount":1,"screenShotPaths":[],"testParams":{"lib":"myDirarrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDirarrow/config/config.js","test":"demo/test-greeter.js","page":"myDirarrow/lib/client/testHost.html","customController":false},"startTime":1399316871519,"endTime":1399316873297,"driver":{"logger":{"category":"NodeDriver","_events":{}},"config":{"seleniumHost":"http://localhost:4444/wd/hub","phantomHost":"http://localhost:4445/wd/hub","context":"","defaultAppHost":"","logLevel":"INFO","browser":"firefox","parallel":false,"baseUrl":"","arrowModuleRoot":"myDirarrow/","dimensions":"myDirarrow/config/dimensions.json","defaultTestHost":"myDirarrow/lib/client/testHost.html","defaultAppSeed":"//cdnjs.cloudflare.com/ajax/libs/yui/3.15.0/yui-min.js","autolib":"myDirarrow/lib/common","useYUISandbox":false,"sandboxYUIVersion":"3.8.0","yuiSandboxRuntime":"myDirarrow/lib/client/yui-test-runtime.js","engine":"yui","engineConfig":"","testSeed":"myDirarrow/lib/client/yuitest-seed.js","testRunner":"myDirarrow/lib/client/yuitest-runner.js","shareLibPath":["myDirarrow/sharelib","./common"],"scanShareLibPrefix":[],"scanShareLibRecursive":true,"enableShareLibYUILoader":false,"descriptorName":"test_descriptor.json","minPort":10000,"maxPort":11000,"coverage":false,"coverageExclude":"","exitCode":true,"retryCount":0,"keepIstanbulCoverageJson":false,"color":true,"report":true,"testTimeOut":30000,"ignoreSslErrorsPhantomJs":true,"startPhantomJs":false,"startArrowServer":false,"lib":"demo/greeter.js","artifactsUrl":""},"webdriver":null,"testName":"Default","args":{"config":{},"params":{"lib":"myDirarrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDirarrow/config/config.js","test":"demo/test-greeter.js","page":"myDirarrow/lib/client/testHost.html","customController":false},"testName":"Default","driver":"nodejs","browser":""},"reports":{"logger":{"category":"ReportStack","_events":{}},"report":{"results":[{"name":"Our First Test","passed":0,"failed":1,"errors":0,"ignored":0,"total":1,"duration":5,"type":"report","testCase_yui_3_8_0_1_1399316872731_6":{"name":"testCase_yui_3_8_0_1_1399316872731_6","passed":0,"failed":1,"errors":0,"ignored":0,"total":1,"duration":4,"type":"testcase","test greet":{"result":"fail","message":"Values should be equal.\nExpected: Smith, Joe (string)\nActual: Smith, JoeX (string)","type":"test","name":"test greet","duration":0}},"timestamp":"Mon May 05 2014 12:07:52 GMT-0700 (PDT)","ua":"nodejs"}]},"stkReportAtom":[{"results":[{"name":"Our First Test","passed":0,"failed":1,"errors":0,"ignored":0,"total":1,"duration":5,"type":"report","testCase_yui_3_8_0_1_1399316872731_6":{"name":"testCase_yui_3_8_0_1_1399316872731_6","passed":0,"failed":1,"errors":0,"ignored":0,"total":1,"duration":4,"type":"testcase","test greet":{"result":"fail","message":"Values should be equal.\nExpected: Smith, Joe (string)\nActual: Smith, JoeX (string)","type":"test","name":"test greet","duration":0}},"timestamp":"Mon May 05 2014 12:07:52 GMT-0700 (PDT)","ua":"nodejs"}]}]},"arrowServerBase":"","isMobile":false}}],"arrWDSessions":[],"driver":"nodejs","testSuiteName":"ARROW TESTSUITE","timeReport":{"undefined":[]}}; + + var ss = new SessionFactory({},{}); + A.isTrue(ss.isFailure(reportObj), "Report Object contains failure. isFailure() should return true"); + + }, + + testExitFailureTrueScenario: function() { + + var reportObj = + {"reportFolder":"arrow-target","arrTestSessions":[{"logger":{"category":"TestSession","_events":{}},"args":{"config":{},"params":{"lib":"myDir/arrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDir/arrow/config/config.js","test":"demo/test-greeter.js","page":"myDir/arrow/lib/client/testHost.html","customController":false},"testName":"Default","driver":"nodejs","browser":""},"config":{"seleniumHost":"http://localhost:4444/wd/hub","phantomHost":"http://localhost:4445/wd/hub","context":"","defaultAppHost":"","logLevel":"INFO","browser":"firefox","parallel":false,"baseUrl":"","arrowModuleRoot":"myDir/arrow/","dimensions":"myDir/arrow/config/dimensions.json","defaultTestHost":"myDir/arrow/lib/client/testHost.html","defaultAppSeed":"//cdnjs.cloudflare.com/ajax/libs/yui/3.15.0/yui-min.js","autolib":"myDir/arrow/lib/common","useYUISandbox":false,"sandboxYUIVersion":"3.8.0","yuiSandboxRuntime":"myDir/arrow/lib/client/yui-test-runtime.js","engine":"yui","engineConfig":"","testSeed":"myDir/arrow/lib/client/yuitest-seed.js","testRunner":"myDir/arrow/lib/client/yuitest-runner.js","shareLibPath":["myDir/arrow/sharelib","./common"],"scanShareLibPrefix":[],"scanShareLibRecursive":true,"enableShareLibYUILoader":false,"descriptorName":"test_descriptor.json","minPort":10000,"maxPort":11000,"coverage":false,"coverageExclude":"","exitCode":true,"retryCount":0,"keepIstanbulCoverageJson":false,"color":true,"report":true,"testTimeOut":30000,"ignoreSslErrorsPhantomJs":true,"startPhantomJs":false,"startArrowServer":false,"lib":"demo/greeter.js","artifactsUrl":""},"driverName":"nodejs","testConfig":{},"retryCount":1,"screenShotPaths":[],"testParams":{"lib":"myDir/arrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDir/arrow/config/config.js","test":"demo/test-greeter.js","page":"myDir/arrow/lib/client/testHost.html","customController":false},"startTime":1399316871519,"endTime":1399316873297,"driver":{"logger":{"category":"NodeDriver","_events":{}},"config":{"seleniumHost":"http://localhost:4444/wd/hub","phantomHost":"http://localhost:4445/wd/hub","context":"","defaultAppHost":"","logLevel":"INFO","browser":"firefox","parallel":false,"baseUrl":"","arrowModuleRoot":"myDir/arrow/","dimensions":"myDir/arrow/config/dimensions.json","defaultTestHost":"myDir/arrow/lib/client/testHost.html","defaultAppSeed":"//cdnjs.cloudflare.com/ajax/libs/yui/3.15.0/yui-min.js","autolib":"myDir/arrow/lib/common","useYUISandbox":false,"sandboxYUIVersion":"3.8.0","yuiSandboxRuntime":"myDir/arrow/lib/client/yui-test-runtime.js","engine":"yui","engineConfig":"","testSeed":"myDir/arrow/lib/client/yuitest-seed.js","testRunner":"myDir/arrow/lib/client/yuitest-runner.js","shareLibPath":["myDir/arrow/sharelib","./common"],"scanShareLibPrefix":[],"scanShareLibRecursive":true,"enableShareLibYUILoader":false,"descriptorName":"test_descriptor.json","minPort":10000,"maxPort":11000,"coverage":false,"coverageExclude":"","exitCode":true,"retryCount":0,"keepIstanbulCoverageJson":false,"color":true,"report":true,"testTimeOut":30000,"ignoreSslErrorsPhantomJs":true,"startPhantomJs":false,"startArrowServer":false,"lib":"demo/greeter.js","artifactsUrl":""},"webdriver":null,"testName":"Default","args":{"config":{},"params":{"lib":"myDir/arrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDir/arrow/config/config.js","test":"demo/test-greeter.js","page":"myDir/arrow/lib/client/testHost.html","customController":false},"testName":"Default","driver":"nodejs","browser":""},"reports":{"logger":{"category":"ReportStack","_events":{}},"report":{"scenario":[{"results":[{"controller":"myDir/arrow_exitCode/arrow/lib/controller/default","params":{"comment":"Load finance page","page":"http://finance.yahoo.com","lib":"myDir/arrow_exitCode/arrow/lib/common/yui-arrow.js","shared":{},"descriptorSharedParams":{},"customController":false}}]},{"results":[{"controller":"myDir/arrow_exitCode/arrow/lib/controller/locator","params":{"value":"#txtQuotes","text":"yhoo\n","lib":"myDir/arrow_exitCode/arrow/lib/common/yui-arrow.js","shared":{},"descriptorSharedParams":{},"customController":false}}]},{"results":[{"name":"Quote Page test of the test","passed":0,"failed":1,"errors":0,"ignored":0,"total":1,"duration":4,"type":"report","testCase_yui_3_9_1_8_1399325311687_6":{"name":"testCase_yui_3_9_1_8_1399325311687_6","passed":0,"failed":1,"errors":0,"ignored":0,"total":1,"duration":3,"type":"testcase","test quote":{"result":"fail","message":"Values should be equal.\nExpected: undefined (undefined)\nActual: Yahoo! Inc. (YHOO) (string)","type":"test","name":"test quote","duration":1}},"timestamp":"Mon May 5 14:28:32 2014","ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:26.0) Gecko/20100101 Firefox/26.0","currentUrl":"http://finance.yahoo.com/q?s=yhoo&ql=1"}]}]},"stkReportAtom":[{"results":[{"name":"Our First Test","passed":0,"failed":1,"errors":0,"ignored":0,"total":1,"duration":5,"type":"report","testCase_yui_3_8_0_1_1399316872731_6":{"name":"testCase_yui_3_8_0_1_1399316872731_6","passed":0,"failed":1,"errors":0,"ignored":0,"total":1,"duration":4,"type":"testcase","test greet":{"result":"fail","message":"Values should be equal.\nExpected: Smith, Joe (string)\nActual: Smith, JoeX (string)","type":"test","name":"test greet","duration":0}},"timestamp":"Mon May 05 2014 12:07:52 GMT-0700 (PDT)","ua":"nodejs"}]}]},"arrowServerBase":"","isMobile":false}}],"arrWDSessions":[],"driver":"nodejs","testSuiteName":"ARROW TESTSUITE","timeReport":{"undefined":[]}} + + var ss = new SessionFactory({},{}); + A.isTrue(ss.isFailure(reportObj), "Report Object contains failure in scenario. isFailure() should return true"); + + }, + + testExitFailureIfNoReportFound: function() { + + var reportObj = + {"reportFolder":"arrow-target","arrTestSessions":[{"logger":{"category":"TestSession","_events":{}},"args":{"config":{},"params":{"lib":"myDir/arrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDir/arrow/config/config.js","test":"demo/test-greeter.js","page":"myDir/arrow/lib/client/testHost.html","customController":false},"testName":"Default","driver":"nodejs","browser":""},"config":{"seleniumHost":"http://localhost:4444/wd/hub","phantomHost":"http://localhost:4445/wd/hub","context":"","defaultAppHost":"","logLevel":"INFO","browser":"firefox","parallel":false,"baseUrl":"","arrowModuleRoot":"myDir/arrow/","dimensions":"myDir/arrow/config/dimensions.json","defaultTestHost":"myDir/arrow/lib/client/testHost.html","defaultAppSeed":"//cdnjs.cloudflare.com/ajax/libs/yui/3.15.0/yui-min.js","autolib":"myDir/arrow/lib/common","useYUISandbox":false,"sandboxYUIVersion":"3.8.0","yuiSandboxRuntime":"myDir/arrow/lib/client/yui-test-runtime.js","engine":"yui","engineConfig":"","testSeed":"myDir/arrow/lib/client/yuitest-seed.js","testRunner":"myDir/arrow/lib/client/yuitest-runner.js","shareLibPath":["myDir/arrow/sharelib","./common"],"scanShareLibPrefix":[],"scanShareLibRecursive":true,"enableShareLibYUILoader":false,"descriptorName":"test_descriptor.json","minPort":10000,"maxPort":11000,"coverage":false,"coverageExclude":"","exitCode":true,"retryCount":0,"keepIstanbulCoverageJson":false,"color":true,"report":true,"testTimeOut":30000,"ignoreSslErrorsPhantomJs":true,"startPhantomJs":false,"startArrowServer":false,"lib":"demo/greeter.js","artifactsUrl":""},"driverName":"nodejs","testConfig":{},"retryCount":1,"screenShotPaths":[],"testParams":{"lib":"myDir/arrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDir/arrow/config/config.js","test":"demo/test-greeter.js","page":"myDir/arrow/lib/client/testHost.html","customController":false},"startTime":1399320190344,"endTime":1399320192116,"driver":{"logger":{"category":"NodeDriver","_events":{}},"config":{"seleniumHost":"http://localhost:4444/wd/hub","phantomHost":"http://localhost:4445/wd/hub","context":"","defaultAppHost":"","logLevel":"INFO","browser":"firefox","parallel":false,"baseUrl":"","arrowModuleRoot":"myDir/arrow/","dimensions":"myDir/arrow/config/dimensions.json","defaultTestHost":"myDir/arrow/lib/client/testHost.html","defaultAppSeed":"//cdnjs.cloudflare.com/ajax/libs/yui/3.15.0/yui-min.js","autolib":"myDir/arrow/lib/common","useYUISandbox":false,"sandboxYUIVersion":"3.8.0","yuiSandboxRuntime":"myDir/arrow/lib/client/yui-test-runtime.js","engine":"yui","engineConfig":"","testSeed":"myDir/arrow/lib/client/yuitest-seed.js","testRunner":"myDir/arrow/lib/client/yuitest-runner.js","shareLibPath":["myDir/arrow/sharelib","./common"],"scanShareLibPrefix":[],"scanShareLibRecursive":true,"enableShareLibYUILoader":false,"descriptorName":"test_descriptor.json","minPort":10000,"maxPort":11000,"coverage":false,"coverageExclude":"","exitCode":true,"retryCount":0,"keepIstanbulCoverageJson":false,"color":true,"report":true,"testTimeOut":30000,"ignoreSslErrorsPhantomJs":true,"startPhantomJs":false,"startArrowServer":false,"lib":"demo/greeter.js","artifactsUrl":""},"webdriver":null,"testName":"Default","args":{"config":{},"params":{"lib":"myDir/arrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDir/arrow/config/config.js","test":"demo/test-greeter.js","page":"myDir/arrow/lib/client/testHost.html","customController":false},"testName":"Default","driver":"nodejs","browser":""},"reports":{"logger":{"category":"ReportStack","_events":{}},"report":{"results":[]},"stkReportAtom":[]},"arrowServerBase":"","isMobile":false}}],"arrWDSessions":[],"driver":"nodejs","testSuiteName":"ARROW TESTSUITE","timeReport":{"undefined":[]}}; + + var ss = new SessionFactory({},{}); + A.isTrue(ss.isFailure(reportObj), "Report Object does not contain report. isFailure() should return true"); + + }, + + testExitFailureFalse: function() { + + var reportObj = + {"reportFolder":"arrow-target","arrTestSessions":[{"logger":{"category":"TestSession","_events":{}},"args":{"config":{},"params":{"lib":"myDir/arrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDir/arrow/config/config.js","test":"demo/test-greeter.js","page":"myDir/arrow/lib/client/testHost.html","customController":false},"testName":"Default","driver":"nodejs","browser":""},"config":{"seleniumHost":"http://localhost:4444/wd/hub","phantomHost":"http://localhost:4445/wd/hub","context":"","defaultAppHost":"","logLevel":"INFO","browser":"firefox","parallel":false,"baseUrl":"","arrowModuleRoot":"myDir/arrow/","dimensions":"myDir/arrow/config/dimensions.json","defaultTestHost":"myDir/arrow/lib/client/testHost.html","defaultAppSeed":"//cdnjs.cloudflare.com/ajax/libs/yui/3.15.0/yui-min.js","autolib":"myDir/arrow/lib/common","useYUISandbox":false,"sandboxYUIVersion":"3.8.0","yuiSandboxRuntime":"myDir/arrow/lib/client/yui-test-runtime.js","engine":"yui","engineConfig":"","testSeed":"myDir/arrow/lib/client/yuitest-seed.js","testRunner":"myDir/arrow/lib/client/yuitest-runner.js","shareLibPath":["myDir/arrow/sharelib","./common"],"scanShareLibPrefix":[],"scanShareLibRecursive":true,"enableShareLibYUILoader":false,"descriptorName":"test_descriptor.json","minPort":10000,"maxPort":11000,"coverage":false,"coverageExclude":"","exitCode":true,"retryCount":0,"keepIstanbulCoverageJson":false,"color":true,"report":true,"testTimeOut":30000,"ignoreSslErrorsPhantomJs":true,"startPhantomJs":false,"startArrowServer":false,"lib":"demo/greeter.js","artifactsUrl":""},"driverName":"nodejs","testConfig":{},"retryCount":1,"screenShotPaths":[],"testParams":{"lib":"myDir/arrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDir/arrow/config/config.js","test":"demo/test-greeter.js","page":"myDir/arrow/lib/client/testHost.html","customController":false},"startTime":1399320190344,"endTime":1399320192116,"driver":{"logger":{"category":"NodeDriver","_events":{}},"config":{"seleniumHost":"http://localhost:4444/wd/hub","phantomHost":"http://localhost:4445/wd/hub","context":"","defaultAppHost":"","logLevel":"INFO","browser":"firefox","parallel":false,"baseUrl":"","arrowModuleRoot":"myDir/arrow/","dimensions":"myDir/arrow/config/dimensions.json","defaultTestHost":"myDir/arrow/lib/client/testHost.html","defaultAppSeed":"//cdnjs.cloudflare.com/ajax/libs/yui/3.15.0/yui-min.js","autolib":"myDir/arrow/lib/common","useYUISandbox":false,"sandboxYUIVersion":"3.8.0","yuiSandboxRuntime":"myDir/arrow/lib/client/yui-test-runtime.js","engine":"yui","engineConfig":"","testSeed":"myDir/arrow/lib/client/yuitest-seed.js","testRunner":"myDir/arrow/lib/client/yuitest-runner.js","shareLibPath":["myDir/arrow/sharelib","./common"],"scanShareLibPrefix":[],"scanShareLibRecursive":true,"enableShareLibYUILoader":false,"descriptorName":"test_descriptor.json","minPort":10000,"maxPort":11000,"coverage":false,"coverageExclude":"","exitCode":true,"retryCount":0,"keepIstanbulCoverageJson":false,"color":true,"report":true,"testTimeOut":30000,"ignoreSslErrorsPhantomJs":true,"startPhantomJs":false,"startArrowServer":false,"lib":"demo/greeter.js","artifactsUrl":""},"webdriver":null,"testName":"Default","args":{"config":{},"params":{"lib":"myDir/arrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDir/arrow/config/config.js","test":"demo/test-greeter.js","page":"myDir/arrow/lib/client/testHost.html","customController":false},"testName":"Default","driver":"nodejs","browser":""},"reports":{"logger":{"category":"ReportStack","_events":{}},"report":{"results":[{"name":"Our First Test","passed":1,"failed":0,"errors":0,"ignored":0,"total":1,"duration":7,"type":"report","testCase_yui_3_8_0_1_1399320191546_6":{"name":"testCase_yui_3_8_0_1_1399320191546_6","passed":1,"failed":0,"errors":0,"ignored":0,"total":1,"duration":4,"type":"testcase","test greet":{"result":"pass","message":"Test passed","type":"test","name":"test greet","duration":1}},"timestamp":"Mon May 05 2014 13:03:11 GMT-0700 (PDT)","ua":"nodejs"}]},"stkReportAtom":[{"results":[{"name":"Our First Test","passed":1,"failed":0,"errors":0,"ignored":0,"total":1,"duration":7,"type":"report","testCase_yui_3_8_0_1_1399320191546_6":{"name":"testCase_yui_3_8_0_1_1399320191546_6","passed":1,"failed":0,"errors":0,"ignored":0,"total":1,"duration":4,"type":"testcase","test greet":{"result":"pass","message":"Test passed","type":"test","name":"test greet","duration":1}},"timestamp":"Mon May 05 2014 13:03:11 GMT-0700 (PDT)","ua":"nodejs"}]}]},"arrowServerBase":"","isMobile":false}}],"arrWDSessions":[],"driver":"nodejs","testSuiteName":"ARROW TESTSUITE","timeReport":{"undefined":[]}}; + + var ss = new SessionFactory({},{}); + A.isFalse(ss.isFailure(reportObj), "Report Object does not contain failure. isFailure() should return false"); + + }, + + testExitFailureNoReportObj: function() { + + var reportObj = + {"reportFolder":"arrow-target","arrTestSessions":[{"logger":{"category":"TestSession","_events":{}},"args":{"config":{},"params":{"lib":"myDir/arrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDir/arrow/config/config.js","test":"demo/test-greeter.js","page":"myDir/arrow/lib/client/testHost.html","customController":false},"testName":"Default","driver":"nodejs","browser":""},"config":{"seleniumHost":"http://localhost:4444/wd/hub","phantomHost":"http://localhost:4445/wd/hub","context":"","defaultAppHost":"","logLevel":"INFO","browser":"firefox","parallel":false,"baseUrl":"","arrowModuleRoot":"myDir/arrow/","dimensions":"myDir/arrow/config/dimensions.json","defaultTestHost":"myDir/arrow/lib/client/testHost.html","defaultAppSeed":"//cdnjs.cloudflare.com/ajax/libs/yui/3.15.0/yui-min.js","autolib":"myDir/arrow/lib/common","useYUISandbox":false,"sandboxYUIVersion":"3.8.0","yuiSandboxRuntime":"myDir/arrow/lib/client/yui-test-runtime.js","engine":"yui","engineConfig":"","testSeed":"myDir/arrow/lib/client/yuitest-seed.js","testRunner":"myDir/arrow/lib/client/yuitest-runner.js","shareLibPath":["myDir/arrow/sharelib","./common"],"scanShareLibPrefix":[],"scanShareLibRecursive":true,"enableShareLibYUILoader":false,"descriptorName":"test_descriptor.json","minPort":10000,"maxPort":11000,"coverage":false,"coverageExclude":"","exitCode":true,"retryCount":0,"keepIstanbulCoverageJson":false,"color":true,"report":true,"testTimeOut":30000,"ignoreSslErrorsPhantomJs":true,"startPhantomJs":false,"startArrowServer":false,"lib":"demo/greeter.js","artifactsUrl":""},"driverName":"nodejs","testConfig":{},"retryCount":1,"screenShotPaths":[],"testParams":{"lib":"myDir/arrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDir/arrow/config/config.js","test":"demo/test-greeter.js","page":"myDir/arrow/lib/client/testHost.html","customController":false},"startTime":1399320190344,"endTime":1399320192116,"driver":{"logger":{"category":"NodeDriver","_events":{}},"config":{"seleniumHost":"http://localhost:4444/wd/hub","phantomHost":"http://localhost:4445/wd/hub","context":"","defaultAppHost":"","logLevel":"INFO","browser":"firefox","parallel":false,"baseUrl":"","arrowModuleRoot":"myDir/arrow/","dimensions":"myDir/arrow/config/dimensions.json","defaultTestHost":"myDir/arrow/lib/client/testHost.html","defaultAppSeed":"//cdnjs.cloudflare.com/ajax/libs/yui/3.15.0/yui-min.js","autolib":"myDir/arrow/lib/common","useYUISandbox":false,"sandboxYUIVersion":"3.8.0","yuiSandboxRuntime":"myDir/arrow/lib/client/yui-test-runtime.js","engine":"yui","engineConfig":"","testSeed":"myDir/arrow/lib/client/yuitest-seed.js","testRunner":"myDir/arrow/lib/client/yuitest-runner.js","shareLibPath":["myDir/arrow/sharelib","./common"],"scanShareLibPrefix":[],"scanShareLibRecursive":true,"enableShareLibYUILoader":false,"descriptorName":"test_descriptor.json","minPort":10000,"maxPort":11000,"coverage":false,"coverageExclude":"","exitCode":true,"retryCount":0,"keepIstanbulCoverageJson":false,"color":true,"report":true,"testTimeOut":30000,"ignoreSslErrorsPhantomJs":true,"startPhantomJs":false,"startArrowServer":false,"lib":"demo/greeter.js","artifactsUrl":""},"webdriver":null,"testName":"Default","args":{"config":{},"params":{"lib":"myDir/arrow/lib/common/yui-arrow.js,demo/greeter.js","driver":"nodejs","report":true,"exitCode":true,"argv":{"remain":["demo/test-greeter.js"],"cooked":["demo/test-greeter.js","--lib","demo/greeter.js","--driver","nodejs","--report","true","--exitCode","true"],"original":["demo/test-greeter.js","--lib=demo/greeter.js","--driver=nodejs","--report=true","--exitCode=true"]},"config":"myDir/arrow/config/config.js","test":"demo/test-greeter.js","page":"myDir/arrow/lib/client/testHost.html","customController":false},"testName":"Default","driver":"nodejs","browser":""},"reports":{"logger":{"category":"ReportStack","_events":{}},"stkReportAtom":[{"results":[{"name":"Our First Test","passed":1,"failed":0,"errors":0,"ignored":0,"total":1,"duration":7,"type":"report","testCase_yui_3_8_0_1_1399320191546_6":{"name":"testCase_yui_3_8_0_1_1399320191546_6","passed":1,"failed":0,"errors":0,"ignored":0,"total":1,"duration":4,"type":"testcase","test greet":{"result":"pass","message":"Test passed","type":"test","name":"test greet","duration":1}},"timestamp":"Mon May 05 2014 13:03:11 GMT-0700 (PDT)","ua":"nodejs"}]}]},"arrowServerBase":"","isMobile":false}}],"arrWDSessions":[],"driver":"nodejs","testSuiteName":"ARROW TESTSUITE","timeReport":{"undefined":[]}}; + + var ss = new SessionFactory({},{}); + A.isFalse(ss.isFailure(reportObj), "Report Object does not have report. isFailure() should return false"); + + }, + + testExitFailureFalseEmptyReportObj: function() { + + var reportObj = + {}; + + var ss = new SessionFactory({},{}); + A.isFalse(ss.isFailure(reportObj), "Report Object does not contain failure. isFailure() should return false"); + + } + + })); + + suite.add(new Y.Test.Case({ + + name : "Call getFactoryTests with no config", + + testGetFactoryTestWithDescriptorSharedParams: function() { + var ss = new SessionFactory({"dimensions" : arrowRoot + "/config/dimensions.json", "arrowModuleRoot" : arrowRoot + "/", "arrDescriptor": [__dirname + "/testdata/test_descriptor_noConfig.json"]}, + {}), + t; + t = ss.getFactoryTests(); + A.areEqual(2, t.length, "There should be 2 test objects"); + + } + })); + + suite.add(new Y.Test.Case({ + + name : "Call getFactoryTests with descriptor importing", + + testGetFactoryTestWithDescriptorImporting: function() { + Y.log("dir:" + __dirname); + var ss = new SessionFactory({"dimensions" : arrowRoot + "/config/dimensions.json", "arrowModuleRoot" : arrowRoot + "/", "arrDescriptor" : [__dirname + "/testdata/test_descriptor_importDescriptor.json"]}, {}), + t, + expectedLibPath = __dirname + "/testdata/lib/test-imported-lib.js"; + + global.workingDirectory = arrowRoot; + + t = ss.getFactoryTests(); + + A.areEqual(3, t.length, "There should be 3 test objects"); + A.areEqual(expectedLibPath, t[2].params.lib, "lib of imprted descriptor should be composed with correct relative path"); + } + })); + Y.Test.Runner.add(suite); diff --git a/tests/unit/lib/session/testdata/config.js b/tests/unit/lib/session/testdata/config.js index 4f5b2194..5575116c 100644 --- a/tests/unit/lib/session/testdata/config.js +++ b/tests/unit/lib/session/testdata/config.js @@ -22,6 +22,6 @@ config.defaultAppSeed = "http://yui.yahooapis.com/3.4.1/build/yui/yui-min.js"; config.testSeed = config.arrowModuleRoot + "lib/client/yuitest-seed.js"; config.testRunner = config.arrowModuleRoot + "lib/client/yuitest-runner.js"; config.autolib = config.arrowModuleRoot + "lib/common"; -config.descriptorName = "test_descriptor.json"; +config.descriptorPath = "test_descriptor.json"; module.exports = config; diff --git a/tests/unit/lib/session/testdata/configdata.json b/tests/unit/lib/session/testdata/configdata.json new file mode 100644 index 00000000..4de01d52 --- /dev/null +++ b/tests/unit/lib/session/testdata/configdata.json @@ -0,0 +1,14 @@ +{ + "config": [ + { + "finance": { + "baseUrl": "http://finance.yahoo.com" + } + }, + { + "yahoo": { + "baseUrl": "http://yahoo.com" + } + } + ] +} \ No newline at end of file diff --git a/tests/unit/lib/session/testdata/datadriven-descriptor.json b/tests/unit/lib/session/testdata/datadriven-descriptor.json new file mode 100644 index 00000000..e0d379f6 --- /dev/null +++ b/tests/unit/lib/session/testdata/datadriven-descriptor.json @@ -0,0 +1,34 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "dataDriver" : "./configdata.json", + + "dataprovider" : { + + "Test Data Driven Descriptor" : { + "group" : "func", + + "params" :{ + + "scenario": [ + { + "page": "$$config.baseUrl$$" + }, + { + "test": "dummytest.js" + } + ] + } + + } + } + }, + { + "settings": [ "environment:development" ] + } + +] + diff --git a/tests/unit/lib/session/testdata/lib/test-imported-lib.js b/tests/unit/lib/session/testdata/lib/test-imported-lib.js new file mode 100644 index 00000000..b83286e7 --- /dev/null +++ b/tests/unit/lib/session/testdata/lib/test-imported-lib.js @@ -0,0 +1,18 @@ +YUI.add("import-lib", function(Y) { + + var Assert = Y.Assert; + + var self = Y.namespace("Media.Test").ImportTestLib = { + + testUrl : function(url) { + setTimeout(function() { + Y.log('[Logger] Browser now Loading URL [' + url + ']'); + window.open(targetUrl, '_self'); + }, timeout); + } + + }; + +}, "0.1", { + requires : ["test", "node"] +}); diff --git a/tests/unit/lib/session/testdata/test_descriptor_importDescriptor.json b/tests/unit/lib/session/testdata/test_descriptor_importDescriptor.json new file mode 100644 index 00000000..7cde31d1 --- /dev/null +++ b/tests/unit/lib/session/testdata/test_descriptor_importDescriptor.json @@ -0,0 +1,44 @@ +[ + { + "settings": [ "master" ], + "name" : "tabview", + "commonlib" : "lib/session/testdata/test-lib.js", + "config" :{ + "baseUrl" : "my.com", + "testsValue": "sometest.js" + }, + + "importDescriptor":[ + { + "path" : "../importDescriptor/importDescriptorWithTestLib.json", + "group" : "func" + } + ], + + "dataprovider" : { + + "base test 1" : { + "params" : { + "test" : "test-func.js", + "page" : "testMock.html" + }, + "group" : "unit" + }, + + "base test 2" : { + "params" : { + "test" : "$$config.testsValue$$", + "page" : "$$config.baseUrl$$/testMock.html" + }, + "group" : "func" + } + } + }, + { + "settings": [ "environment:development" ], + + "config" :{ + "baseUrl" : "http://dimensions.url.override.com" + } + } +] \ No newline at end of file diff --git a/tests/unit/lib/session/testdata/test_descriptor_noConfig.json b/tests/unit/lib/session/testdata/test_descriptor_noConfig.json new file mode 100755 index 00000000..1c013d97 --- /dev/null +++ b/tests/unit/lib/session/testdata/test_descriptor_noConfig.json @@ -0,0 +1,36 @@ +[ + { + "settings": [ "master" ], + + "name" : "tabview", + + "commonlib" : "lib/session/testdata/test-lib.js", + + "dataprovider" : { + "testWithInvalidLib" : { + "params" : { + "test" : "lib/session/testdata/test-func1.js", + "page" : "testMock.html", + "lib" : "Not Found Lib" + } + }, + + "testWithMultipleBrowsers" : { + "params" : { + "test" : "lib/session/testdata/test-int.js", + "page" : "abc.com/media/test_common/lego_test/demo/tabview/src/tabview.html", + "lib" : "lib/session/testdata/test-lib.js" + }, + "browser" : "firefox,opera" + } + + + } + + }, + + { + "settings": [ "environment:development" ] + } + +] diff --git a/tests/unit/lib/session/testdata/test_descriptor_shared_params.json b/tests/unit/lib/session/testdata/test_descriptor_shared_params.json new file mode 100755 index 00000000..d683d784 --- /dev/null +++ b/tests/unit/lib/session/testdata/test_descriptor_shared_params.json @@ -0,0 +1,64 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "config": { + + "baseUrl": "http://finance.yahoo.com", + + "descriptorSharedParams" :{ + "yhooquote": "Yahoo", + "applequote": "Apple" + } + }, + + "dataprovider" : { + + "Test YHOO Ticker" : { + "group" : "func", + + "params" :{ + + "scenario": [ + { + "page": "$$config.baseUrl$$" + }, + { + "controller": "locator", + "params": { + "value": "#txtQuotes", + "text": "yhoo\n" + } + }, + { + "test": "test-quote-yhoo-shared-params.js" + }, + + { + "page": "$$config.baseUrl$$" + }, + { + "controller": "locator", + "params": { + "value": "#txtQuotes", + "text": "aapl\n" + } + }, + { + "test": "test-quote-aapl-shared-params.js" + } + + ] + } + + } + } + }, + { + "settings": [ "environment:development" ] + } + +] + diff --git a/tests/unit/lib/session/testsession-tests.js b/tests/unit/lib/session/testsession-tests.js index 85c2a9c9..3f567703 100644 --- a/tests/unit/lib/session/testsession-tests.js +++ b/tests/unit/lib/session/testsession-tests.js @@ -145,6 +145,26 @@ YUI.add('testsession-tests', function (Y) { } })); + suite.add(new Y.Test.Case({ + + name : "Check for invalid driver", + + testInvalidDriver: function(){ + var config = {}, + args = {}; + + args.params = {}; + args.params.driver="invalid"; + var ts = new testSession(config,args,null); + + ts.setup(function(msg){ + A.isTrue(msg.indexOf("ERROR :invalid is not a supported test driver, Please provide \"selenium\" or \"nodejs\" as driver.") > -1 , "Should return invalid driver"); + }); + + } + })); + + suite.add(new Y.Test.Case({ name : "Get Artifact Paths test with report Folder", @@ -160,7 +180,7 @@ YUI.add('testsession-tests', function (Y) { var obj = {}; obj.count = 1; obj.testName = "Test-1"; - obj.descriptorPath = "descriptorPath"; + obj.qualifiedDescriptorPath = "descriptorPath"; obj.reportDir = "myReport/arrow-target"; obj.screenShotsDir = "screenshots"; @@ -180,7 +200,6 @@ YUI.add('testsession-tests', function (Y) { try { var fileUtil = new FileUtil(); fileUtil.removeDirectory(path.resolve(process.cwd(), "myReport/arrow-target")); - console.log('Cleaned up arrow-target dir.'); } catch(e){ } @@ -197,7 +216,7 @@ YUI.add('testsession-tests', function (Y) { var obj = {}; obj.count = 1; obj.testName = "Test-1"; - obj.descriptorPath = "descriptorPath"; + obj.qualifiedDescriptorPath = "descriptorPath"; obj.reportDir = "myReport/arrow-target"; obj.screenShotsDir = "screenshots"; obj.artifactsUrl = "http://ci.com/artifacts/tests/arrow/node/myReport/arrow-target"; @@ -225,7 +244,6 @@ YUI.add('testsession-tests', function (Y) { try { var fileUtil = new FileUtil(); fileUtil.removeDirectory(path.resolve(process.cwd(), "myReport/arrow-target")); - console.log('Cleaned up arrow-target dir.'); } catch(e){ } @@ -250,7 +268,7 @@ YUI.add('testsession-tests', function (Y) { var obj = {}; obj.count = 1; obj.testName = "Test-1"; - obj.descriptorPath = "descriptorPath"; + obj.qualifiedDescriptorPath = "descriptorPath"; obj.reportDir = "arrow-target"; obj.screenShotsDir = "screenshots"; @@ -271,7 +289,6 @@ YUI.add('testsession-tests', function (Y) { try { var fileUtil = new FileUtil(); fileUtil.removeDirectory(path.resolve(process.cwd(), "myReport/arrow-target")); - console.log('Cleaned up arrow-target dir.'); } catch(e){ } @@ -289,7 +306,7 @@ YUI.add('testsession-tests', function (Y) { var obj = {}; obj.count = 1; obj.testName = "Test-1"; - obj.descriptorPath = "descriptorPath"; + obj.qualifiedDescriptorPath = "descriptorPath"; obj.reportDir = "arrow-target"; obj.screenShotsDir = "screenshots"; obj.artifactsUrl = "http://ci.com/artifacts/tests/arrow/node/arrow-target"; @@ -317,7 +334,6 @@ YUI.add('testsession-tests', function (Y) { try { var fileUtil = new FileUtil(); fileUtil.removeDirectory(path.resolve(process.cwd(), "myReport/arrow-target")); - console.log('Cleaned up arrow-target dir.'); } catch(e){ } @@ -326,6 +342,35 @@ YUI.add('testsession-tests', function (Y) { } })); + suite.add(new Y.Test.Case({ + + name : "Update Sauce labs result", + + testUpdateSauceLabsPass: function() { + + var ts = new testSession({},{},null), + log4js = require("log4js"), + mockery = require('mockery'), + logger = log4js.getLogger("TestSession"), + sauceLabsMock = require(arrowRoot + '/tests/unit/stub/SauceLabs'); + + sauceLabsMock.prototype.updateJob = function(result, id, callback){ + callback(null); + } + + mockery.registerMock('saucelabs', sauceLabsMock); + mockery.enable(); + + ts.updateSauceLabs("pass","testName", "SessionId", "username", "accesskey", + logger, function(error){ + A.isNull(error); + mockery.deregisterMock('sauceLabs'); + mockery.disable(); + }); + } + + })); + Y.Test.Runner.add(suite); }, '0.0.1', {requires:['test']}); diff --git a/tests/unit/lib/util/base.json b/tests/unit/lib/util/base.json new file mode 100644 index 00000000..8b9b8c6b --- /dev/null +++ b/tests/unit/lib/util/base.json @@ -0,0 +1,9 @@ +[ + { + "settings": [ "environment:new" ], + + "config" :{ + "baseUrl" : "http://newurl.com" + } + } +] diff --git a/tests/unit/lib/util/capabilitymanager-tests.js b/tests/unit/lib/util/capabilitymanager-tests.js index 5fbc8fb5..63a93fd1 100644 --- a/tests/unit/lib/util/capabilitymanager-tests.js +++ b/tests/unit/lib/util/capabilitymanager-tests.js @@ -22,7 +22,7 @@ YUI.add('capabilitymanager-tests', function(Y) { })); suite.add(new Y.Test.Case({ - "Confirm getCapability works": function(){ + "Confirm getCapability works if JSON filepath passed": function(){ var expectedString = {"browserName":"firefox","platform":"WINDOWS","version":"6.0","javascriptEnabled":"true"}; var cap = cm.getCapability(__dirname + "/capabilities.json", "win_xp_ff_6"); Y.Assert.areEqual(JSON.stringify(expectedString), JSON.stringify(cap), "Confirm the same JSON is returned"); @@ -34,6 +34,229 @@ YUI.add('capabilitymanager-tests', function(Y) { })); + suite.add(new Y.Test.Case({ + "Confirm getCapability is null if both JSON blob or filePath is invalid": function(){ + var expectedString = {"browserName":"firefox","platform":"WINDOWS","version":"6.0","javascriptEnabled":"true"}; + var cap = cm.getCapability(__dirname + "/capabilities2.json", "win_xp_ff_6"); + Y.Assert.areEqual(null, cap, "Caps JSON shall be null"); + + } + })); + + + suite.add(new Y.Test.Case({ + "Confirm getCapability works if JSON blob passed": function(){ + var caps = "{\"capabilities\": {\"win_xp_ff_6\": {\"browserName\": \"firefox\",\"platform\": \"WINDOWS\",\"version\": \"6.0\"},\"mac_chrome_18\": {" + + "\"browserName\": \"chrome\",\"platform\": \"MAC\",\"version\": \"18.0\"}},\"common_capabilities\": {\"javascriptEnabled\": \"true\"}}"; + var expectedString = {"browserName":"firefox","platform":"WINDOWS","version":"6.0","javascriptEnabled":"true"}; + var cap = cm.getCapability(caps, "win_xp_ff_6"); + Y.Assert.areEqual(JSON.stringify(expectedString), JSON.stringify(cap), "Confirm the same JSON is returned"); + + //Make sure null is returned and invalid capability is given + cap = cm.getCapability("", "invalid"); + Y.Assert.isNull(cap, "Confirm null is returned if invalid cap is given"); + } + })); + + + suite.add(new Y.Test.Case({ + "Test proxy capabilities - proxy true": function(){ + + var args = {}, + caps = {}; + + args.proxyUrl='someHost:10000'; + args.proxy = true; + + caps = cm.setProxyCaps(caps, args); + + Y.Assert.areEqual('someHost:10000',caps.proxy.httpProxy,"Http Proxy url doesnt match"); + Y.Assert.areEqual('someHost:10000',caps.proxy.sslProxy,"Ssl Proxy url doesnt match"); + Y.Assert.areEqual('manual',caps.proxy.proxyType,"proxy type doesnt match"); + + } + })); + + + suite.add(new Y.Test.Case({ + "Test proxy capabilities - proxy undefined": function(){ + + var args = {}, + caps = {}; + + args.proxyUrl='someHost:10000'; + + caps = cm.setProxyCaps(caps, args); + + Y.Assert.areEqual('someHost:10000',caps.proxy.httpProxy,"Http Proxy url doesnt match"); + Y.Assert.areEqual('someHost:10000',caps.proxy.sslProxy,"Ssl Proxy url doesnt match"); + Y.Assert.areEqual('manual',caps.proxy.proxyType,"proxy type doesnt match"); + + } + })); + + + suite.add(new Y.Test.Case({ + "Test proxy capabilities - proxy false": function(){ + + var args = {}, + caps = {}; + + args.proxyUrl='someHost:10000'; + args.proxy = false; + + caps = cm.setProxyCaps(caps, args); + Y.Assert.isUndefined(caps.proxy, ' Caps proxy should be undefined if proxy set to false'); + + } + })); + + + suite.add(new Y.Test.Case({ + "Test proxy capabilities": function(){ + + var args = {}, + caps = {}; + + args.proxyUrl='someHost:10000'; + args.proxy = true; + + caps = cm.setProxyCaps(caps, args); + + Y.Assert.areEqual('someHost:10000',caps.proxy.httpProxy,"Http Proxy url doesnt match"); + Y.Assert.areEqual('someHost:10000',caps.proxy.sslProxy,"Ssl Proxy url doesnt match"); + Y.Assert.areEqual('manual',caps.proxy.proxyType,"proxy type doesnt match"); + + } + })); + + + suite.add(new Y.Test.Case({ + "Test mobile capabilities": function(){ + + var args = {}, + caps = {}; + + caps.browserName = "iphone"; + caps.version = "latest"; + + args.proxyUrl='someHost:10000'; + args.proxy = true; + + caps = cm.setMobileCaps(caps); + + Y.Assert.areEqual('iphone',caps.deviceName,"Caps deviceName should be iphone"); + Y.Assert.areEqual('iOS',caps.platformName,"Caps platformName should be iOS"); + Y.Assert.areEqual('Safari',caps.browserName,"Caps browserName should be Safari"); + + } + })); + + + suite.add(new Y.Test.Case({ + "Test browser caps for reuse and proxy": function(){ + + var args = {}, + caps = {}, + config = {}; + + caps.browserName = "reuse"; + caps.proxy = { + "httpProxy": "someHost:10000", + "sslProxy": "someHost:10000", + "proxyType": "manual" + }; + + caps = cm.setBrowserCaps(caps, args, config); + + Y.Assert.areEqual('firefox',caps.browserName,"Caps browser should be firefox"); + Y.Assert.areEqual('latest',caps.version,"Caps version should be latest"); + } + })); + + + suite.add(new Y.Test.Case({ + + "Test process user capabilities": function(){ + + var caps = { + "platform": "ANY", + "javascriptEnabled": true, + "seleniumProtocol": "WebDriver" + }; + caps.browserName = "mac_chrome_18"; + + var config = {}; + config.capabilities = __dirname + "/capabilities.json"; + config.browser = "mac_chrome_18"; + + caps = cm.processUserCapabilities(caps,config); + + Y.Assert.areEqual('WebDriver',caps.seleniumProtocol,"Caps seleniumProtocol should be WebDriver"); + Y.Assert.isTrue(true,caps.javascriptEnabled,"Caps javascriptEnabled should be true"); + Y.Assert.areEqual('chrome',caps.browserName,"Caps browserName should be chrome"); + Y.Assert.areEqual('MAC',caps.platform,"Caps platform should be MAC"); + Y.Assert.areEqual('18.0',caps.version,"Caps version should be 18.0"); + + } + })); + + suite.add(new Y.Test.Case({ + "Test Sauce capabilities - passed in config": function(){ + var args = {}, + caps = {}, + config = {}; + config.isSauceLabs = true; + config.sauceUsername = "sauceuser"; + config.sauceAccesskey = "saucekey"; + config.sauceTunnel = "sauceTunnel"; + + caps = cm.setSauceCaps(caps, config); + + Y.Assert.areEqual('sauceuser',caps.username, "Capabilities username doesnt match when passed from config"); + Y.Assert.areEqual('saucekey',caps.accessKey, "Capabilities accesskey doesnt match when passed from config"); + Y.Assert.areEqual('sauceTunnel',caps['parent-tunnel'], "Capabilities parent-tunnel doesnt match when passed from config"); + } + })); + + suite.add(new Y.Test.Case({ + "Test Sauce capabilities - isSauceLabs false": function(){ + var args = {}, + caps = {}, + config = {}; + + config.isSauceLabs = false; + caps = cm.setSauceCaps(caps, config); + + Y.Assert.isUndefined(caps.username, "Capabilities username should be undefined"); + Y.Assert.isUndefined(caps.accessKey, "Capabilities accesskey should be undefined"); + Y.Assert.isUndefined(caps['parent-tunnel'], "Capabilities parent-tunnel should be undefined"); + } + })); + + + + suite.add(new Y.Test.Case({ + "Test Sauce capabilities - passed in environment": function(){ + var args = {}, + caps = {}, + config = {}; + config.isSauceLabs = true; + process.env.SAUCE_USERNAME = "sauceuser"; + process.env.SAUCE_ACCESS_KEY = "saucekey"; + process.env.SAUCE_TUNNEL = "sauceTunnel"; + + caps = cm.setSauceCaps(caps, config); + + Y.Assert.areEqual('sauceuser',caps.username, "Capabilities username doesnt match when passed from environment"); + Y.Assert.areEqual('saucekey',caps.accessKey, "Capabilities accesskey doesnt match when passed from environment"); + Y.Assert.areEqual('sauceTunnel',caps['parent-tunnel'], "Capabilities accesskey doesnt match when passed from environment"); + + delete process.env.SAUCE_USERNAME; + delete process.env.SAUCE_ACCESS_KEY; + } + })); + Y.Test.Runner.add(suite); }, '0.0.1' ,{requires:['test']}); \ No newline at end of file diff --git a/tests/unit/lib/util/config/configoverride.js b/tests/unit/lib/util/config/configoverride.js index 4f9e3cd7..12d5e16c 100644 --- a/tests/unit/lib/util/config/configoverride.js +++ b/tests/unit/lib/util/config/configoverride.js @@ -10,6 +10,6 @@ var config = {}; config.parallel = true; config.baseUrl = "http://new.base.url.com"; // Framework config -config.descriptorName = "new_test_descriptor.json"; +config.qualifiedDescriptorPath = "new_test_descriptor.json"; module.exports = config; diff --git a/tests/unit/lib/util/config/descriptor-schema.json b/tests/unit/lib/util/config/descriptor-schema.json index 66c8ef2a..18305565 100644 --- a/tests/unit/lib/util/config/descriptor-schema.json +++ b/tests/unit/lib/util/config/descriptor-schema.json @@ -4,24 +4,60 @@ "properties" : { "name" : { "type" : "string", "required" :true }, "commonlib" : { "type" : "string"}, + "useSSL" : { "type" : "boolean"}, + "extends" : { "type" : "string"}, + "startProxyServer" : { "type" : "boolean"}, + "routerProxyConfig" : { "type" : "string"}, + "comment" : { "type" : "string"}, "config" : { "type" : "object" }, + + "dataDriver":{"type": "string"}, + + "importDescriptor":{ + "type":"array", + "items":[ + { + "path":"Path of the imported file", + "type":"string", + "required":true + }, + { + "group":"Group of tests to import", + "type":"string" + }, + { + "test":"test names to import", + "type":"array" + } + ] + }, + "dataprovider" : { "type":"object", "required":true, "additionalProperties" : { "type" : "object", "properties" : { + "enabled" : { "type" : "boolean | string" }, + "comment" : { "type" : "string"}, "enabled" : { "type" : "boolean" }, "controller" : { "type" : "string" }, "group" : { "type" : "string" }, + "proxy" : { "type" : "boolean" }, "browser" : { "type" : "string" }, + "testTimeOut" : { "type" : "integer" }, + "hasTest" : { "type" : "boolean" }, + "reuseSession" : { "type" : "boolean" }, + "relativePath" : { "type" : "string" }, "params" : {"type" : "object", "properties" : { "page" : { "type" : "string" }, "test" : { "type" : "string" }, - "lib" : { "type" : "string" } + "lib" : { "type" : "string" }, + "engine" :{ "type" : "string" }, + "engineConfig" :{ "type" : "string" } } } diff --git a/tests/unit/lib/util/config/invalid.txt b/tests/unit/lib/util/config/invalid.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/lib/util/config/reportObject.json b/tests/unit/lib/util/config/reportObject.json index 6d48fb73..81dc69ff 100644 --- a/tests/unit/lib/util/config/reportObject.json +++ b/tests/unit/lib/util/config/reportObject.json @@ -8,7 +8,7 @@ "args": { "config": {}, "params": { - "lib": "/Users/pranavp/Documents/arrow/lib/common/yui-arrow.js,../src/greeter.js", + "lib": "myDir/arrow/lib/common/yui-arrow.js,../src/greeter.js", "report": true, "argv": { "remain": [ @@ -28,7 +28,7 @@ ] }, "test": "test-greeter.js", - "page": "/Users/pranavp/Documents/arrow/lib/client/testHost.html", + "page": "myDir/arrow/lib/client/testHost.html", "customController": false }, "testName": "Default", @@ -43,13 +43,13 @@ "browser": "firefox", "parallel": false, "baseUrl": "", - "arrowModuleRoot": "/Users/pranavp/Documents/arrow/", - "dimensions": "/Users/pranavp/Documents/arrow/config/dimensions.json", - "defaultTestHost": "/Users/pranavp/Documents/arrow/lib/client/testHost.html", + "arrowModuleRoot": "myDir/arrow/", + "dimensions": "myDir/arrow/config/dimensions.json", + "defaultTestHost": "myDir/arrow/lib/client/testHost.html", "defaultAppSeed": "http://yui.yahooapis.com/3.6.0/build/yui/yui-min.js", - "testSeed": "/Users/pranavp/Documents/arrow/lib/client/yuitest-seed.js", - "testRunner": "/Users/pranavp/Documents/arrow/lib/client/yuitest-runner.js", - "autolib": "/Users/pranavp/Documents/arrow/lib/common", + "testSeed": "myDir/arrow/lib/client/yuitest-seed.js", + "testRunner": "myDir/arrow/lib/client/yuitest-runner.js", + "autolib": "myDir/arrow/lib/common", "descriptorName": "test_descriptor.json", "minPort": 10000, "maxPort": 11000, @@ -64,7 +64,7 @@ "testConfig": {}, "retryCount": 0, "testParams": { - "lib": "/Users/pranavp/Documents/arrow/lib/common/yui-arrow.js,../src/greeter.js", + "lib": "myDir/arrow/lib/common/yui-arrow.js,../src/greeter.js", "report": true, "argv": { "remain": [ @@ -84,7 +84,7 @@ ] }, "test": "test-greeter.js", - "page": "/Users/pranavp/Documents/arrow/lib/client/testHost.html", + "page": "myDir/arrow/lib/client/testHost.html", "customController": false }, "driver": { @@ -101,13 +101,13 @@ "browser": "firefox", "parallel": false, "baseUrl": "", - "arrowModuleRoot": "/Users/pranavp/Documents/arrow/", - "dimensions": "/Users/pranavp/Documents/arrow/config/dimensions.json", - "defaultTestHost": "/Users/pranavp/Documents/arrow/lib/client/testHost.html", + "arrowModuleRoot": "myDir/arrow/", + "dimensions": "myDir/arrow/config/dimensions.json", + "defaultTestHost": "myDir/arrow/lib/client/testHost.html", "defaultAppSeed": "http://yui.yahooapis.com/3.6.0/build/yui/yui-min.js", - "testSeed": "/Users/pranavp/Documents/arrow/lib/client/yuitest-seed.js", - "testRunner": "/Users/pranavp/Documents/arrow/lib/client/yuitest-runner.js", - "autolib": "/Users/pranavp/Documents/arrow/lib/common", + "testSeed": "myDir/arrow/lib/client/yuitest-seed.js", + "testRunner": "myDir/arrow/lib/client/yuitest-runner.js", + "autolib": "myDir/arrow/lib/common", "descriptorName": "test_descriptor.json", "minPort": 10000, "maxPort": 11000, @@ -123,7 +123,7 @@ "args": { "config": {}, "params": { - "lib": "/Users/pranavp/Documents/arrow/lib/common/yui-arrow.js,../src/greeter.js", + "lib": "myDir/arrow/lib/common/yui-arrow.js,../src/greeter.js", "report": true, "argv": { "remain": [ @@ -143,7 +143,7 @@ ] }, "test": "test-greeter.js", - "page": "/Users/pranavp/Documents/arrow/lib/client/testHost.html", + "page": "myDir/arrow/lib/client/testHost.html", "customController": false }, "testName": "Default", diff --git a/tests/unit/lib/util/config/resultreportResultNotPresent.json b/tests/unit/lib/util/config/resultreportResultNotPresent.json index 6aea8604..e8ff50ec 100644 --- a/tests/unit/lib/util/config/resultreportResultNotPresent.json +++ b/tests/unit/lib/util/config/resultreportResultNotPresent.json @@ -30,6 +30,6 @@ }, "timestamp": "Tue Feb 12 19:31:12 2013", "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:16.0) Gecko/20100101 Firefox/16.0", - "currentUrl": "http://localhost:10000/arrow/static/Users/pranavp/Documents/arrow_master/arrow/docs/arrow_tutorial/func_test/test/testMock.html" + "currentUrl": "http://localhost:10000/arrow/static/myDir/arrow/docs/arrow_tutorial/func_test/test/testMock.html" } diff --git a/tests/unit/lib/util/configdata-duplicatekeys.json b/tests/unit/lib/util/configdata-duplicatekeys.json new file mode 100644 index 00000000..74c5783e --- /dev/null +++ b/tests/unit/lib/util/configdata-duplicatekeys.json @@ -0,0 +1,14 @@ +{ + "config": [ + { + "yahoo": { + "baseUrl": "http://finance.yahoo.com" + } + }, + { + "yahoo": { + "baseUrl": "http://yahoo.com" + } + } + ] +} \ No newline at end of file diff --git a/tests/unit/lib/util/configdata.json b/tests/unit/lib/util/configdata.json new file mode 100644 index 00000000..4de01d52 --- /dev/null +++ b/tests/unit/lib/util/configdata.json @@ -0,0 +1,14 @@ +{ + "config": [ + { + "finance": { + "baseUrl": "http://finance.yahoo.com" + } + }, + { + "yahoo": { + "baseUrl": "http://yahoo.com" + } + } + ] +} \ No newline at end of file diff --git a/tests/unit/lib/util/datadriven-descriptor-config-context.json b/tests/unit/lib/util/datadriven-descriptor-config-context.json new file mode 100644 index 00000000..8ad603e1 --- /dev/null +++ b/tests/unit/lib/util/datadriven-descriptor-config-context.json @@ -0,0 +1,57 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "config": [ + { + "finance": { + "baseUrl": "http://finance.yahoo.com" + } + }, + { + "yahoo": { + "baseUrl": "http://yahoo.com" + } + } + ], + + "dataprovider" : { + + "Test Data Driven Descriptor" : { + "group" : "func", + + "params" :{ + + "scenario": [ + { + "page": "$$config.baseUrl$$" + }, + { + "test": "dummytest.js" + } + ] + } + + } + } + }, + { + "settings": [ "environment:development" ], + "config": [ + { + "finance": { + "baseUrl": "http://uk.finance.yahoo.com" + } + }, + { + "yahoo": { + "baseUrl": "http://uk.yahoo.com" + } + } + ] + } + +] + diff --git a/tests/unit/lib/util/datadriven-descriptor-config-empty.json b/tests/unit/lib/util/datadriven-descriptor-config-empty.json new file mode 100644 index 00000000..e0e0ecef --- /dev/null +++ b/tests/unit/lib/util/datadriven-descriptor-config-empty.json @@ -0,0 +1,36 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "config": [ + + ], + + "dataprovider" : { + + "Test Data Driven Descriptor" : { + "group" : "func", + + "params" :{ + + "scenario": [ + { + "page": "$$config.baseUrl$$" + }, + { + "test": "dummytest.js" + } + ] + } + + } + } + }, + { + "settings": [ "environment:development" ] + } + +] + diff --git a/tests/unit/lib/util/datadriven-descriptor-config.json b/tests/unit/lib/util/datadriven-descriptor-config.json new file mode 100644 index 00000000..59a8a3f3 --- /dev/null +++ b/tests/unit/lib/util/datadriven-descriptor-config.json @@ -0,0 +1,45 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "config": [ + { + "finance": { + "baseUrl": "http://finance.yahoo.com" + } + }, + { + "yahoo": { + "baseUrl": "http://yahoo.com" + } + } + ], + + "dataprovider" : { + + "Test Data Driven Descriptor" : { + "group" : "func", + + "params" :{ + + "scenario": [ + { + "page": "$$config.baseUrl$$" + }, + { + "test": "dummytest.js" + } + ] + } + + } + } + }, + { + "settings": [ "environment:development" ] + } + +] + diff --git a/tests/unit/lib/util/datadriven-descriptor-dup-keys.json b/tests/unit/lib/util/datadriven-descriptor-dup-keys.json new file mode 100644 index 00000000..a9e5a8ce --- /dev/null +++ b/tests/unit/lib/util/datadriven-descriptor-dup-keys.json @@ -0,0 +1,34 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "dataDriver" : "./configdata-duplicatekeys.json", + + "dataprovider" : { + + "Test Data Driven Descriptor" : { + "group" : "func", + + "params" :{ + + "scenario": [ + { + "page": "$$config.baseUrl$$" + }, + { + "test": "dummytest.js" + } + ] + } + + } + } + }, + { + "settings": [ "environment:development" ] + } + +] + diff --git a/tests/unit/lib/util/datadriven-descriptor-invalid.json b/tests/unit/lib/util/datadriven-descriptor-invalid.json new file mode 100644 index 00000000..37d5a0e8 --- /dev/null +++ b/tests/unit/lib/util/datadriven-descriptor-invalid.json @@ -0,0 +1,34 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "dataDriver" : "./fileDoesNotExist.json", + + "dataprovider" : { + + "Test Data Driven Descriptor" : { + "group" : "func", + + "params" :{ + + "scenario": [ + { + "page": "$$config.baseUrl$$" + }, + { + "test": "dummytest.js" + } + ] + } + + } + } + }, + { + "settings": [ "environment:development" ] + } + +] + diff --git a/tests/unit/lib/util/datadriven-descriptor.json b/tests/unit/lib/util/datadriven-descriptor.json new file mode 100644 index 00000000..e0d379f6 --- /dev/null +++ b/tests/unit/lib/util/datadriven-descriptor.json @@ -0,0 +1,34 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "dataDriver" : "./configdata.json", + + "dataprovider" : { + + "Test Data Driven Descriptor" : { + "group" : "func", + + "params" :{ + + "scenario": [ + { + "page": "$$config.baseUrl$$" + }, + { + "test": "dummytest.js" + } + ] + } + + } + } + }, + { + "settings": [ "environment:development" ] + } + +] + diff --git a/tests/unit/lib/util/datadrivermanager-tests.js b/tests/unit/lib/util/datadrivermanager-tests.js new file mode 100644 index 00000000..b582d77c --- /dev/null +++ b/tests/unit/lib/util/datadrivermanager-tests.js @@ -0,0 +1,266 @@ +/*jslint forin:true sub:true anon:true, sloppy:true, stupid:true nomen:true, node:true continue:true*/ + +/* + * Copyright (c) 2012, Yahoo! Inc. All rights reserved. + * Copyrights licensed under the New BSD License. + * See the accompanying LICENSE file for terms. + */ + +YUI.add('datadrivermanager-tests', function (Y) { + + var fs = require("fs"); + var path = require('path'), + arrowRoot = path.join(__dirname, '../../../..'), + DataDriverMgr = require(arrowRoot+'/lib/util/datadrivermanager.js'), + suite = new Y.Test.Suite("Data Driver Manager test suite"); + + var dataDriverMgr = new DataDriverMgr(); + + dataDriverMgr.mock = { + exit: function (code) { + throw new Error("exit code is "+code); + } + }; + + suite.add(new Y.Test.Case({ + + "get config data from file": function() { + + var + descPath = __dirname + '/datadriven-descriptor.json', + descriptorJsonStr = fs.readFileSync(descPath, 'utf-8'), + relativePath = path.dirname(descPath), + descriptorJson, + configArr; + + try { + + descriptorJson = JSON.parse(descriptorJsonStr); + configArr = dataDriverMgr.getConfigData(relativePath, descriptorJson); + }catch(e) { + + } + + Y.Assert.isNotUndefined(configArr, "Config array is undefined ( getting from file)"); + Y.Assert.areEqual(2, configArr.length); + + Y.Assert.areEqual('http://finance.yahoo.com', configArr[0]['finance']['baseUrl'], "Config baseurl ( 0th element doesn't match )"); + Y.Assert.areEqual('http://yahoo.com', configArr[1]['yahoo']['baseUrl'], "Config baseurl ( 1st element doesn't match )"); + + }, + + "get config data from array": function() { + + var + descPath = __dirname + '/datadriven-descriptor-config.json', + descriptorJsonStr = fs.readFileSync(descPath, 'utf-8'), + descriptorJson, + configArr; + + try { + descriptorJson = JSON.parse(descriptorJsonStr); + configArr = dataDriverMgr.getConfigData(descPath, descriptorJson); + }catch(e) { + + } + + Y.Assert.isNotUndefined(configArr, "Config array is undefined (getting from config array)"); + Y.Assert.areEqual(2, configArr.length); + + Y.Assert.areEqual('http://finance.yahoo.com', configArr[0]['finance']['baseUrl'], "Config baseurl ( 0th element doesn't match"); + Y.Assert.areEqual('http://yahoo.com', configArr[1]['yahoo']['baseUrl'], "Config baseurl ( 1st element doesn't match"); + + }, + + "empty configuration": function() { + + var + descPath = __dirname + '/datadriven-descriptor-config-empty.json', + descriptorJsonStr = fs.readFileSync(descPath, 'utf-8'), + descriptorJson, + descriptorArr, + msg; + + try { + descriptorJson = JSON.parse(descriptorJsonStr); + descriptorArr = dataDriverMgr.processDataDriver(descPath, descriptorJson); + }catch(e) { + + msg = e.message; + } + + Y.Assert.areEqual("exit code is 1", msg); + + + }, + + "duplicate keys in config data": function() { + + var + descPath = __dirname + '/configdata-duplicatekeys.json', + configDataStr = fs.readFileSync(descPath, 'utf-8'), + configObj, + errMsg; + + try { + configObj = JSON.parse(configDataStr); + dataDriverMgr.checkForDuplicateKeys(configObj.config); + }catch(e) { + errMsg = e.message; + } + +// Y.Assert.isTrue(errMsg.indexOf('Duplicate key \'yahoo\' in the object') > -1); + + Y.Assert.isNotUndefined(errMsg, "Process data driver with duplicate keys in config data shall throw exception"); + if (errMsg) { + Y.Assert.isTrue(errMsg.indexOf('Duplicate key \'yahoo\' in the object') > -1); + } + + + } + + + ,"unique keys in config data": function() { + + var + descPath = __dirname + '/configdata.json', + configDataStr = fs.readFileSync(descPath, 'utf-8'), + configObj, + errMsg; + + try { + configObj = JSON.parse(configDataStr); + dataDriverMgr.checkForDuplicateKeys(configObj.config); + }catch(e) { + errMsg = e.message; + } + + Y.Assert.isUndefined(errMsg, "No exception shall be thrown when keys are unique"); + + } + + + + })); + + suite.add(new Y.Test.Case({ + + "process data driver ": function() { + + var + descPath = __dirname + '/datadriven-descriptor.json', + descriptorJsonStr = fs.readFileSync(descPath, 'utf-8'), + descriptorJson, + descriptorArr = []; + + try { + descriptorJson = JSON.parse(descriptorJsonStr); + descriptorArr = dataDriverMgr.processDataDriver(descPath, descriptorJson); + + Y.Assert.areEqual( 2, descriptorArr.length); + + var desc0 = '[{"settings":["master"],"name":"controllers","dataDriver":"./configdata.json","dataprovider":{"Test Data Driven Descriptor":{"group":"func","params":{"scenario":[{"page":"$$config.baseUrl$$"},{"test":"dummytest.js"}]}}},"config":{"baseUrl":"http://finance.yahoo.com"},"dataDriverKey":"finance"},{"settings":["environment:development"]}]'; + Y.Assert.areEqual(desc0, JSON.stringify(descriptorArr[0])); + + var desc1 = '[{"settings":["master"],"name":"controllers","dataDriver":"./configdata.json","dataprovider":{"Test Data Driven Descriptor":{"group":"func","params":{"scenario":[{"page":"$$config.baseUrl$$"},{"test":"dummytest.js"}]}}},"config":{"baseUrl":"http://yahoo.com"},"dataDriverKey":"yahoo"},{"settings":["environment:development"]}]'; + + Y.Assert.areEqual(desc1, JSON.stringify(descriptorArr[1])); + + }catch(e) { + Y.Assert.fail(e); + } + + }, + + + "process data driver with context": function() { + + var + descPath = __dirname + '/datadriven-descriptor-config-context.json', + descriptorJsonStr = fs.readFileSync(descPath, 'utf-8'), + descriptorJson, + descriptorArr = []; + + try { + + descriptorJson = JSON.parse(descriptorJsonStr); + descriptorArr = dataDriverMgr.processDataDriver(descPath, descriptorJson); + + Y.Assert.areEqual( 2, descriptorArr.length); + + var desc0 = '[{"settings":["master"],"name":"controllers","config":{"baseUrl":"http://finance.yahoo.com"},"dataprovider":{"Test Data Driven Descriptor":{"group":"func","params":{"scenario":[{"page":"$$config.baseUrl$$"},{"test":"dummytest.js"}]}}},"dataDriverKey":"finance"},{"settings":["environment:development"],"config":{"baseUrl":"http://uk.finance.yahoo.com"}}]'; + var desc1 = '[{"settings":["master"],"name":"controllers","config":{"baseUrl":"http://yahoo.com"},"dataprovider":{"Test Data Driven Descriptor":{"group":"func","params":{"scenario":[{"page":"$$config.baseUrl$$"},{"test":"dummytest.js"}]}}},"dataDriverKey":"yahoo"},{"settings":["environment:development"],"config":{"baseUrl":"http://uk.yahoo.com"}}]'; + + Y.Assert.areEqual(desc0, JSON.stringify(descriptorArr[0]), "Descriptor Array 0 value doesn't match"); + Y.Assert.areEqual(desc1, JSON.stringify(descriptorArr[1]) , "Descriptor Array 0 value doesn't match"); + + + + }catch(e) { + Y.Assert.fail(e); + } + + }, + + "process data driver duplicate keys ": function() { + + var + descPath = __dirname + '/datadriven-descriptor-dup-keys.json', + descriptorJsonStr = fs.readFileSync(descPath, 'utf-8'), + descriptorJson, + descriptorArr = [], + errMsg; + + try { + descriptorJson = JSON.parse(descriptorJsonStr); + descriptorArr = dataDriverMgr.processDataDriver(descPath, descriptorJson); + + }catch(e) { + errMsg = e.message; + } + + Y.Assert.isNotUndefined(errMsg, "Process data driver with duplicate keys in config data shall throw exception"); + + if (errMsg) { + Y.Assert.isTrue(errMsg.indexOf("exit code is 1") > -1); + } + + } + + })); + + suite.add(new Y.Test.Case({ + + "process data driver invalid config file": function() { + + var + descPath = __dirname + '/datadriven-descriptor-invalid.json', + descriptorJsonStr = fs.readFileSync(descPath, 'utf-8'), + descriptorJson, + msg; + + try { + + descriptorJson = JSON.parse(descriptorJsonStr); + dataDriverMgr.getConfigData(descPath, descriptorJson); + + }catch(e) { + msg = e.message; + } + + Y.Assert.areEqual("exit code is 1",msg,'Error message doesnt match when data driven descriptor is invalid' ); + + + } + })); + + + Y.Test.Runner.add(suite); +}, '0.0.1', {requires:['test']}); + + + + + + + \ No newline at end of file diff --git a/tests/unit/lib/util/dataprovider-tests.js b/tests/unit/lib/util/dataprovider-tests.js index 64ee7f74..9106f081 100644 --- a/tests/unit/lib/util/dataprovider-tests.js +++ b/tests/unit/lib/util/dataprovider-tests.js @@ -25,6 +25,12 @@ YUI.add('dataprovider-tests', function (Y) { var dp = new dataProv(conf, args, __dirname + "/testDescriptor.json"); var dpvalues = dp.getTestData(); + dp.mock = { + exit: function (code) { + throw new Error("exit code is "+code); + } + }; + suite.add(new Y.Test.Case({ "Confirm constructor works": function(){ Y.Assert.isNotNull(dp, "Confirm initiallizing does not return null"); @@ -34,25 +40,25 @@ YUI.add('dataprovider-tests', function (Y) { //Test getting all values in a descriptor suite.add(new Y.Test.Case({ "Confirm Config params": function(){ - Y.Assert.areEqual("tabview", dpvalues.name); - Y.Assert.areEqual("./test-lib.js", dpvalues.commonlib); - Y.Assert.areEqual(":8033", dpvalues.config.baseUrl); + Y.Assert.areEqual("tabview", dpvalues[0].name); + Y.Assert.areEqual("./test-lib.js", dpvalues[0].commonlib); + Y.Assert.areEqual(":8033", dpvalues[0].config.baseUrl); } })); suite.add(new Y.Test.Case({ "Confirm dataprovider values": function(){ - Y.Assert.areEqual("test-func.js", dpvalues.dataprovider.test1.params.test); - Y.Assert.areEqual("testMock.html", dpvalues.dataprovider.test1.params.page); - Y.Assert.areEqual("unit", dpvalues.dataprovider.test1.group); + Y.Assert.areEqual("test-func.js", dpvalues[0].dataprovider.test1.params.test); + Y.Assert.areEqual("testMock.html", dpvalues[0].dataprovider.test1.params.page); + Y.Assert.areEqual("unit", dpvalues[0].dataprovider.test1.group); } })); //Test overriding values in the descriptor using $$ value suite.add(new Y.Test.Case({ "Confirm you can share config values within descriptor": function(){ - Y.Assert.areEqual(":8033/testMock.html", dpvalues.dataprovider.test2.params.page); - Y.Assert.areEqual("sometest.js", dpvalues.dataprovider.test2.params.test); + Y.Assert.areEqual(":8033/testMock.html", dpvalues[0].dataprovider.test2.params.page); + Y.Assert.areEqual("sometest.js", dpvalues[0].dataprovider.test2.params.test); } })); @@ -68,10 +74,17 @@ YUI.add('dataprovider-tests', function (Y) { args = {}; var dp = new dataProv(conf, args, __dirname + "/testDescriptor.json"); + + dp.mock = { + exit: function (code) { + throw new Error("exit code is "+code); + } + }; + var dpvalues = dp.getTestData(); - Y.Assert.areEqual("http://overridebase.url.com/testMock.html", dpvalues.dataprovider.test2.params.page); - Y.Assert.areEqual("sometest.js", dpvalues.dataprovider.test2.params.test); + Y.Assert.areEqual("http://overridebase.url.com/testMock.html", dpvalues[0].dataprovider.test2.params.page); + Y.Assert.areEqual("sometest.js", dpvalues[0].dataprovider.test2.params.test); } })); @@ -89,10 +102,15 @@ YUI.add('dataprovider-tests', function (Y) { args = {}; var dp = new dataProv(conf, args,__dirname + "/testDescriptor.json"); + dp.mock = { + exit: function (code) { + throw new Error("exit code is "+code); + } + }; var dpvalues = dp.getTestData(); - Y.Assert.areEqual("http://overridebase.url.com/testMock.html", dpvalues.dataprovider.test2.params.page); - Y.Assert.areEqual("sometest.js", dpvalues.dataprovider.test2.params.test); + Y.Assert.areEqual("http://overridebase.url.com/testMock.html", dpvalues[0].dataprovider.test2.params.page); + Y.Assert.areEqual("sometest.js", dpvalues[0].dataprovider.test2.params.test); } })); @@ -145,6 +163,114 @@ YUI.add('dataprovider-tests', function (Y) { } })); + + suite.add(new Y.Test.Case({ + + "Invalid json from file": function() { + + var msg; + + try { + dp.readAndValidateJSON(__dirname + '/invalid.json'); + } + catch(e) { + msg = e; + } + Y.Assert.areEqual( "exit code is 1", msg.message,"readAndValidateJSON() did not throw exception for invalid JSON from file"); + } + })); + + + suite.add(new Y.Test.Case({ + + "Invalid json ": function() { + + var msg; + + try { + dp.readAndValidateJSON('{\'a\'}'); + } + catch(e) { + msg = e; + } + Y.Assert.areEqual( "exit code is 1", msg.message, "readAndValidateJSON() did not throw exception for invalid JSON"); + } + })); + + + suite.add(new Y.Test.Case({ + + "Invalid descriptorjson ": function() { + + var conf = {}, + args = {}; + + var dp = new dataProv(conf, args,__dirname + "/invalid.json"); + var msg; + dp.mock = { + exit: function (code) { + throw new Error("exit code is "+code); + } + }; + + + try { + dp.getTestData(); + } + catch(e) { + msg = e; + } + Y.Assert.areEqual( "exit code is 1", msg.message, "getTestData() did not throw exception for invalid JSON"); + } + })); + + + suite.add(new Y.Test.Case({ + + "Validate descriptor against schema ": function() { + + var msg, + descriptor; + + try { + + descriptor = fs.readFileSync(__dirname + '/testDescriptorInvalidSchema.json','utf-8'); + descriptor = JSON.parse(descriptor); + dp.validateDescriptor(descriptor, __dirname + "/config/descriptor-schema.json"); + + } + catch(e) { + msg = e; + } + + Y.Assert.areEqual( "exit code is 1", msg.message, "validateDescriptor() did not throw exception for invalid schema"); + + } + })); + + suite.add(new Y.Test.Case({ + + "Validate descriptor against schema - wrong path for schema ": function() { + + var msg, + descriptor; + + try { + + descriptor = fs.readFileSync(__dirname + '/testDescriptorInvalidSchema.json','utf-8'); + descriptor = JSON.parse(descriptor); + dp.validateDescriptor(descriptor, __dirname + "/config/descriptor-schema-invalid.json"); + + } + catch(e) { + msg = e; + } + + Y.Assert.areEqual( "exit code is 1", msg.message, "validateDescriptor() did not throw exception for invalid schema file"); + + } + })); + suite.add(new Y.Test.Case({ "Replace params": function(){ var conf = { @@ -167,7 +293,6 @@ YUI.add('dataprovider-tests', function (Y) { } })); - suite.add(new Y.Test.Case({ "Replace params and default params": function(){ var conf = { @@ -240,6 +365,83 @@ YUI.add('dataprovider-tests', function (Y) { } })); + suite.add(new Y.Test.Case({ + + "Data driven descriptor test": function(){ + + var conf = { + "baseUrl": "http://overridebase.url.com", + "arrowModuleRoot": __dirname + "/", + "dimensions": __dirname + "/dimensions.json", + "context": "" + }, + args = {}; + + var dp = new dataProv(conf, args, __dirname + "/datadriven-descriptor.json"); + dp.mock = { + exit: function (code) { + throw new Error("exit code is "+code); + } + }; + var dpvalues = dp.getTestData(); + + Y.Assert.areEqual(2, dpvalues.length, 'Number of data driven descriptors dont match'); + +// Y.Assert.areEqual("http://overridebase.url.com/testMock.html", dpvalues[0].dataprovider.test2.params.page); +// Y.Assert.areEqual("sometest.js", dpvalues[0].dataprovider.test2.params.test); + + } + })); + + suite.add(new Y.Test.Case({ + + "Test extends": function(){ + + var conf = { + "baseUrl": "http://mybaseurl.com", + "arrowModuleRoot": __dirname + "/", + "dimensions": __dirname + "/dimensions.json", + "context": "environment:development", + "replaceParamJSON" : __dirname + "/replaceParams/replaceParam.json", + "defaultParamJSON" : __dirname + "/replaceParams/defaultParam.json" + }, + args = {}; + + var descPath = __dirname + '/testDescriptorExtends.json'; + var dp = new dataProv(conf, args,descPath); + var descriptor = JSON.parse(fs.readFileSync(descPath,'utf-8')); + var relativePath = path.dirname(dp.testDataPath); + + descriptor = dp.processExtendDescriptor(descriptor, __dirname, relativePath); + Y.Assert.isNotUndefined(descriptor,'Descriptor is undefined after extends'); + Y.Assert.areEqual(2, descriptor.length,'Length of descriptor Array shall be 2'); + Y.Assert.areEqual('{"settings":["environment:new"],"config":{"baseUrl":"http://newurl.com"}}', JSON.stringify(descriptor[1]), "descriptor[1] doesnt match the expected value after extending"); + } + })); + + suite.add(new Y.Test.Case({ + + "Apply YCB substitution - Settings has already been added test ": function() { + + var msg, + descriptor, + contextObj = {}; + + try { + + descriptor = fs.readFileSync(__dirname + '/descriptor-invalid-settings.json', 'utf-8'); + descriptor = JSON.parse(descriptor); + dp.applyYcbSubstitution(descriptor, contextObj); + + } catch (e) { + msg = e; + } + + Y.Assert.areEqual("exit code is 1", msg.message, "validateDescriptor() did not throw exception for invalid schema file"); + + } + })); + Y.Test.Runner.add(suite); }, '0.0.1', {requires:['test']}); diff --git a/tests/unit/lib/util/descriptor-invalid-settings.json b/tests/unit/lib/util/descriptor-invalid-settings.json new file mode 100644 index 00000000..80ec558e --- /dev/null +++ b/tests/unit/lib/util/descriptor-invalid-settings.json @@ -0,0 +1,57 @@ +[ + { + "settings": [ "master" ], + + "name": "controllers", + + "dataDriver" : "./configData.json", + + "dataprovider" : { + + "Test Data Driven Descriptor" : { + "group" : "func", + + "params" :{ + + "scenario": [ + { + "page": "$$config.baseUrl$$" + }, + { + "test": "dummytest.js" + } + ] + } + + } + } + }, + { + "settings": [ "master" ], + + "name": "controllers", + + "dataDriver" : "./configData.json", + + "dataprovider" : { + + "Test Data Driven Descriptor" : { + "group" : "func", + + "params" :{ + + "scenario": [ + { + "page": "$$config.baseUrl$$" + }, + { + "test": "dummytest.js" + } + ] + } + + } + } + } +] + diff --git a/tests/unit/lib/util/errormanager-tests.js b/tests/unit/lib/util/errormanager-tests.js index 02ea8a00..dd1061a3 100644 --- a/tests/unit/lib/util/errormanager-tests.js +++ b/tests/unit/lib/util/errormanager-tests.js @@ -17,26 +17,26 @@ YUI.add('errormanager-tests', function(Y) { em, msg, suite = new Y.Test.Suite("Error Manager test suite"), - origDim = - [ - { - "dimensions": [ - { - "environment": { - "development": { - "dev": null, - "test": null - }, - "productions": { - "int": null, - "stage": null, - "prod": null + origDim = + [ + { + "dimensions": [ + { + "environment": { + "development": { + "dev": null, + "test": null + }, + "productions": { + "int": null, + "stage": null, + "prod": null + } } } - } - ] - } - ], + ] + } + ], descSchema = { "name" : "test", "type" : "object", @@ -111,7 +111,7 @@ YUI.add('errormanager-tests', function(Y) { } messages.push(message); } - mocks.message = messages; + mocks.message = messages; }, exit: function (code) { mocks.invokeCount = mocks.invokeCount + 1; @@ -328,8 +328,8 @@ YUI.add('errormanager-tests', function(Y) { Y.Assert.areSame( '1000 (EDIMENVTEST) The environment "qa1" is missing.\nPlease add environment "qa1" to dimensions file "./config/dimensions.json".', mocks.message[mocks.message.length-1] - ); - Y.Assert.areSame(1, mocks.invokeCount); + ); + Y.Assert.areSame(1, mocks.invokeCount); } } })); @@ -355,8 +355,8 @@ YUI.add('errormanager-tests', function(Y) { Y.Assert.areSame( '1006 (ENULLARGTEST) Argument "seleniumHost" is "null".', mocks.message[mocks.message.length-1] - ); - Y.Assert.areSame(1, mocks.invokeCount); + ); + Y.Assert.areSame(1, mocks.invokeCount); } } })); @@ -384,8 +384,8 @@ YUI.add('errormanager-tests', function(Y) { Y.Assert.areSame( '1006 (ENULLARGTEST) Argument "seleniumHost" is "null".', mocks.message[mocks.message.length-1] - ); - Y.Assert.areSame(1, mocks.invokeCount); + ); + Y.Assert.areSame(1, mocks.invokeCount); } } })); @@ -409,10 +409,10 @@ YUI.add('errormanager-tests', function(Y) { Y.Assert.areSame("exit code is 1", exit, "should exit with exit code."); Y.Assert.areSame( '1003 (EDSCENVTEST) The settings {"environment":"sss"} is missing.\n'+ - 'Please add environment "sss" to dimensions file "./config/dimensions.json"\n'+ - 'or remove it from test descriptor file "test-descriptor.json".', + 'Please add environment "sss" to dimensions file "./config/dimensions.json"\n'+ + 'or remove it from test descriptor file "test-descriptor.json".', mocks.message[mocks.message.length-1] - ); + ); Y.Assert.areSame(1, mocks.invokeCount); } } @@ -441,9 +441,9 @@ YUI.add('errormanager-tests', function(Y) { Y.Assert.areSame("exit code is 1", exit, "should exit with exit code."); Y.Assert.areSame( '1005 (EDSCYCBTEST) YCB Variable Replacement Failed, Please check you descriptor file, test-descriptor.json.\n'+ - "Error: The settings group '{}' has already been added.", + "Error: The settings group '{}' has already been added.", mocks.message[mocks.message.length-1] - ); + ); Y.Assert.areSame(1, mocks.invokeCount); } } diff --git a/tests/unit/lib/util/importDescriptor/baseDescriptorMultipleImport.json b/tests/unit/lib/util/importDescriptor/baseDescriptorMultipleImport.json new file mode 100644 index 00000000..ca5c40bb --- /dev/null +++ b/tests/unit/lib/util/importDescriptor/baseDescriptorMultipleImport.json @@ -0,0 +1,48 @@ +[ + { + "settings": [ "master" ], + "name" : "tabview", + "commonlib" : "./test-lib.js", + "config" :{ + "baseUrl" : "my.com", + "testsValue": "sometest.js" + }, + + "importDescriptor":[ + { + "path" : "./importDescriptorWithLib.json", + "group": "smoke" + }, + { + "path": "./importDescriptorWithLib2.json", + "group": "func" + } + ], + + "dataprovider" : { + + "base test 1" : { + "params" : { + "test" : "test-func.js", + "page" : "testMock.html" + }, + "group" : "unit" + }, + + "base test 2" : { + "params" : { + "test" : "$$config.testsValue$$", + "page" : "$$config.baseUrl$$/testMock.html" + }, + "group" : "func" + } + } + }, + { + "settings": [ "environment:development" ], + + "config" :{ + "baseUrl" : "http://dimensions.url.override.com" + } + } +] \ No newline at end of file diff --git a/tests/unit/lib/util/importDescriptor/importDescriptorWithLib2.json b/tests/unit/lib/util/importDescriptor/importDescriptorWithLib2.json new file mode 100644 index 00000000..34b0633d --- /dev/null +++ b/tests/unit/lib/util/importDescriptor/importDescriptorWithLib2.json @@ -0,0 +1,36 @@ +[ + { + "settings":[ "master" ], + + "name":"controllers", + + "commonlib" : "./imported-test-lib-3.js,./imported-test-lib-4.js", + + "config":{ + "baseUrl":"http://finance.yahoo.com" + }, + + "dataprovider":{ + + "imported test 3":{ + "group":"func", + "params":{ + "page":"$$config.baseUrl$$", + "test":"test.js" + } + }, + + "imported test 4":{ + "group":"smoke", + "params":{ + "page":"$$config.baseUrl$$", + "test":"test.js" + } + } + + } + }, + { + "settings":[ "environment:development" ] + } +] diff --git a/tests/unit/lib/util/importmanager-tests.js b/tests/unit/lib/util/importmanager-tests.js index 5d0bfcfc..24b85a11 100644 --- a/tests/unit/lib/util/importmanager-tests.js +++ b/tests/unit/lib/util/importmanager-tests.js @@ -227,6 +227,38 @@ YUI.add('importmanager-tests', function (Y) { })); + suite.add(new Y.Test.Case({ + + "Import descriptor - multiple descriptors import": function(){ + + var impMgr = new importManager(); + var baseDescriptorPath = '/tests/unit/lib/util/importDescriptor/baseDescriptorMultipleImport.json'; + var descriptorJson = fs.readFileSync(path.join(arrowRoot,baseDescriptorPath),'utf-8'); + descriptorJson = JSON.parse(descriptorJson); + var cwd = process.cwd(); + var group = ''; + + var processedDescJson = impMgr.processImportDescriptor(baseDescriptorPath, cwd, group, descriptorJson); + processedDescJson = JSON.stringify(processedDescJson); + + var expectedDescJson = "[{\"settings\":[\"master\"]," + + "\"name\":\"tabview\"," + + "\"commonlib\":\"./test-lib.js,/tests/unit/lib/util/importDescriptor/imported-test-lib.js,/tests/unit/lib/util/importDescriptor/imported-test-lib-2.js,/tests/unit/lib/util/importDescriptor/imported-test-lib-3.js,/tests/unit/lib/util/importDescriptor/imported-test-lib-4.js\"," + + "\"config\":{\"baseUrl\":\"my.com\",\"testsValue\":\"sometest.js\"}," + + "\"dataprovider\":" + + "{\"base test 1\":{\"params\":{\"test\":\"test-func.js\",\"page\":\"testMock.html\"},\"group\":\"unit\"}," + + "\"base test 2\":{\"params\":{\"test\":\"$$config.testsValue$$\",\"page\":\"$$config.baseUrl$$/testMock.html\"},\"group\":\"func\"}," + + "\"imported test 2\":{\"group\":\"\",\"params\":{\"page\":\"$$config.baseUrl$$\",\"test\":\"test.js\"},\"relativePath\":\"/tests/unit/lib/util/importDescriptor\"}," + + "\"imported test 3\":{\"group\":\"\",\"params\":{\"page\":\"$$config.baseUrl$$\",\"test\":\"test.js\"},\"relativePath\":\"/tests/unit/lib/util/importDescriptor\"}}}," + + "{\"settings\":[\"environment:development\"]," + + "\"config\":{\"baseUrl\":\"http://dimensions.url.override.com\"}}]"; + + Y.Assert.areEqual(expectedDescJson,processedDescJson, "Imported descriptor with base tests - JSON doesn't match"); + + } + + })); + Y.Test.Runner.add(suite); }, '0.0.1', {requires:['test']}); diff --git a/tests/unit/lib/util/invalid.json b/tests/unit/lib/util/invalid.json new file mode 100644 index 00000000..4a433af0 --- /dev/null +++ b/tests/unit/lib/util/invalid.json @@ -0,0 +1,3 @@ +{ + invalid +} \ No newline at end of file diff --git a/tests/unit/lib/util/libmanager-tests.js b/tests/unit/lib/util/libmanager-tests.js index 1da8a9c5..ff88d172 100644 --- a/tests/unit/lib/util/libmanager-tests.js +++ b/tests/unit/lib/util/libmanager-tests.js @@ -29,7 +29,7 @@ YUI.add('libmanager-tests', function (Y) { } })); - //check getAllTests +// //check getAllTests suite.add(new Y.Test.Case({ "Check getAllTest Method": function(){ //Expected is concatenation of the values js and json files in config @@ -46,6 +46,33 @@ YUI.add('libmanager-tests', function (Y) { } })); + suite.add(new Y.Test.Case({ + "Check getAllTest Method space after comma": function(){ + //Expected is concatenation of the values js and json files in config + var libPath = __dirname + "/config/configoverride.js , " + __dirname + '/config/defaultconfig.js'; + var result = libmanager.getAllTest(libPath).split(","); + result.sort(); + + Y.Assert.areEqual(__dirname + "/config/configoverride.js", result[0], "Check Files are Returned"); + Y.Assert.areEqual(__dirname + "/config/defaultconfig.js", result[1], "Check Files are Returned"); + } + })); + + + suite.add(new Y.Test.Case({ + "Check getAllTest Method Invalid library": function(){ + //Expected is concatenation of the values js and json files in config + var libPath = __dirname + "/config/configoverride.js , "; + libPath += __dirname + '/config/defaultconfig.js , '; + libPath += __dirname + '/config/invalid.txt'; + var result = libmanager.getAllTest(libPath).split(","); + result.sort(); + + Y.Assert.areEqual(__dirname + "/config/configoverride.js", result[0], "Check Files are Returned"); + Y.Assert.areEqual(__dirname + "/config/defaultconfig.js", result[1], "Check Files are Returned"); + } + })); + //Check getAllCommonLib suite.add(new Y.Test.Case({ "Check getAllCommonLib method": function(){ diff --git a/tests/unit/lib/util/reportmanager-tests.js b/tests/unit/lib/util/reportmanager-tests.js index 9e53bee0..d0a86676 100644 --- a/tests/unit/lib/util/reportmanager-tests.js +++ b/tests/unit/lib/util/reportmanager-tests.js @@ -407,8 +407,71 @@ YUI.add('reportmanager-tests', function(Y) { } }); - } + }, + + "writeReports With Result Report for data driver" : function() { + var testSessionObj, + arrowRoot = path.join(__dirname, '../../../..'), + TestSession = require(arrowRoot + '/tests/unit/lib/util/testSession.js'), + report = JSON.parse(fs.readFileSync(__dirname + "/config/resultreport.json")), + testSessionsArr = [], + rm, + i, + reportObj, + fileUtil = new FileUtil(); + + + testSessionObj = new TestSession(report); + testSessionObj.args = {}; + testSessionObj.args.browser = "dummyBrowser"; + + testSessionsArr.push(testSessionObj); + + // Instantiate report manager with report object + + reportObj = { + "arrTestSessions" : testSessionsArr, + "arrWDSessions" : "", + "descriptor" : "dummyDescriptor.json", + "reuseSession" : "dummyReuseSession", + "testSuiteName" : "dummyTestSuite", + "driver" : "dummyDriver", + "browser" : "dummyBrowser", + "group" : "dummyGroup", + "testName" : "dummyTestname", + dataDriverKey:"dataDriverKey" + }; + global.reportFolder = "reportFolder"; + global.workingDirectory = process.cwd(); + fileUtil.createDirectory(path.resolve(global.workingDirectory, global.reportFolder, 'arrow-report')); + + rm = new RepManager(reportObj); + + + rm.writeReports(); + + // Clean up + + fs.unlink(path.resolve(global.workingDirectory, global.reportFolder, 'arrow-report', 'dummyDescriptor.json-dataDriverKey-report.json'), + function(err) { + if (err) { + console.log('Can\'t cleanup the dummy descriptor json report file..' + err); + } else { + console.log('Cleaned up the dummy descriptor json report file..'); + } + }); + + fs.unlink(path.resolve(global.workingDirectory, global.reportFolder, 'arrow-report', 'dummyDescriptor.json-dataDriverKey-report.xml'), + function(err) { + if (err) { + console.log('Can\'t cleanup the dummy descriptor xml report file..' + err); + } else { + console.log('Cleaned up the dummy descriptor xml report file..'); + } + }); + + }, diff --git a/tests/unit/lib/util/sauceLabsUtil-tests.js b/tests/unit/lib/util/sauceLabsUtil-tests.js new file mode 100644 index 00000000..63d32842 --- /dev/null +++ b/tests/unit/lib/util/sauceLabsUtil-tests.js @@ -0,0 +1,59 @@ +/*jslint forin:true sub:true anon:true, sloppy:true, stupid:true, nomen:true, node:true continue:true*/ + +/* + * Copyright (c) 2014, Yahoo! Inc. All rights reserved. + * Copyrights licensed under the New BSD License. + * See the accompanying LICENSE file for terms. + */ + +YUI.add('sauceLabsUtil-tests', function (Y) { + + var path = require('path'), + mockery = require('mockery'), + arrowRoot = path.join(__dirname, '../../../..'), + suite = new Y.Test.Suite("SauceLabs Util test suite"), + sauceLabsUtil; + + suite.setUp = function () { + } + + suite.tearDown = function () { + mockery.disable(); + mockery.deregisterAll(); + } + + suite.add(new Y.Test.Case({ + "Update Job Status failed": function(){ + var result = + {"passed":true, "name": 'SauceTestName'}, + sessionId = 'SauceSessionId', + sauceUserName = 'Username', + sauceAccessKey = 'AccessKey', + sauceLabsMock = require(arrowRoot + '/tests/unit/stub/SauceLabs'), + SauceLabsUtil = require(arrowRoot + '/lib/util/sauceLabsUtil.js'), + sauceLabsUtil = new SauceLabsUtil(); + + mockery.registerMock('saucelabs', sauceLabsMock); + mockery.enable(); + + sauceLabsMock.prototype.updateJob = function(sessionId, result, callback) { + callback('error'); + }; + + sauceLabsUtil.updateJobStatus(result, + sessionId, + sauceUserName, + sauceAccessKey, + function (error){ + Y.Assert.isNotNull(error); + Y.Assert.isTrue(error.message.indexOf('Error updating Sauce pass/fail status') > -1, + "Error message does not match"); + mockery.deregisterMock('saucelabs'); + }); + } + + })); + + Y.Test.Runner.add(suite); + +}, '0.0.1', {requires:['test']}); \ No newline at end of file diff --git a/tests/unit/lib/util/testDescriptor.json b/tests/unit/lib/util/testDescriptor.json index 14412341..ffd5d8ae 100644 --- a/tests/unit/lib/util/testDescriptor.json +++ b/tests/unit/lib/util/testDescriptor.json @@ -7,9 +7,11 @@ "baseUrl" : ":8033", "testsValue": "sometest.js" }, + "comment":"This is the comment for master", "dataprovider" : { "test1" : { + "comment":"This is comment for test1", "params" : { "test" : "test-func.js", "page" : "testMock.html" @@ -18,6 +20,7 @@ }, "test2" : { + "comment":"This is comment for test2", "params" : { "test" : "$$config.testsValue$$", "page" : "$$config.baseUrl$$/testMock.html" @@ -27,6 +30,7 @@ } }, { + "comment":"This is the comment for development", "settings": [ "environment:development" ], "config" :{ diff --git a/tests/unit/lib/util/testDescriptorExtends.json b/tests/unit/lib/util/testDescriptorExtends.json new file mode 100644 index 00000000..e5659b94 --- /dev/null +++ b/tests/unit/lib/util/testDescriptorExtends.json @@ -0,0 +1,22 @@ +[ + { + "settings": [ "master" ], + "name" : "tabview", + "commonlib" : "./test-lib.js", + "extends":"./base.json", + "config" :{ + "baseUrl" : ":8033", + "testsValue": "sometest.js" + }, + "dataprovider" : { + + "test1" : { + "params" : { + "test" : "test-func.js", + "page" : "testMock.html" + }, + "group" : "unit" + } + } + } +] \ No newline at end of file diff --git a/tests/unit/lib/util/testDescriptorInvalidSchema.json b/tests/unit/lib/util/testDescriptorInvalidSchema.json new file mode 100644 index 00000000..709e7b96 --- /dev/null +++ b/tests/unit/lib/util/testDescriptorInvalidSchema.json @@ -0,0 +1,36 @@ +[ + { + "settings": [ "master" ], + "name" : "tabview", + "commonlib" : "./test-lib.js", + "config" :{ + "baseUrl" : ":8033", + "testsValue": "sometest.js" + }, + "dataproviderInvalidSchema" : { + + "test1" : { + "params" : { + "test" : "test-func.js", + "page" : "testMock.html" + }, + "group" : "unit" + }, + + "test2" : { + "params" : { + "test" : "$$config.testsValue$$", + "page" : "$$config.baseUrl$$/testMock.html" + }, + "group" : "func" + } + } + }, + { + "settings": [ "environment:development" ], + + "config" :{ + "baseUrl" : "http://dimensions.url.override.com" + } + } +] \ No newline at end of file diff --git a/tests/unit/stub/SauceLabs.js b/tests/unit/stub/SauceLabs.js new file mode 100644 index 00000000..119f3f16 --- /dev/null +++ b/tests/unit/stub/SauceLabs.js @@ -0,0 +1,11 @@ +/* +* Copyright (c) 2014, Yahoo! Inc. All rights reserved. +* Copyrights licensed under the New BSD License. +* See the accompanying LICENSE file for terms. +*/ + +function SauceLabs() { +} + +module.exports = SauceLabs; + diff --git a/tests/unit/stub/driver.js b/tests/unit/stub/driver.js index f35429b4..3edc4fb5 100644 --- a/tests/unit/stub/driver.js +++ b/tests/unit/stub/driver.js @@ -37,10 +37,6 @@ Driver.prototype.navigate = function (page, cb) { } }; -Driver.prototype.executeAction = function (config, params, cb) { - cb(); -}; - Driver.prototype.executeTest = function (config, params, cb) { cb(); }; diff --git a/tests/unit/stub/seleniumserver.js b/tests/unit/stub/seleniumserver.js index af5eef39..efd5104d 100644 --- a/tests/unit/stub/seleniumserver.js +++ b/tests/unit/stub/seleniumserver.js @@ -7,7 +7,7 @@ */ var express = require("express"), - clone = require('clone'); + _ = require('underscore'); function SeleniumServer(port) { @@ -78,7 +78,7 @@ SeleniumServer.prototype.setActiveSessionCount = function(sessionCount) { for(i = 0 ; i < sessionCount ; i = i + 1) { obj = null; - obj = clone(this.sessionObj); + obj = _.clone(this.sessionObj); obj.id = this.sessionsID; this.sessionsID += 1; this.sessions.value.push(obj)