diff --git a/index.js b/index.js index 7cb2c45..95b1c78 100644 --- a/index.js +++ b/index.js @@ -1,25 +1,29 @@ /*───────────────────────────────────────────────────────────────────────────*\ -│ Copyright (C) 2014 eBay Software Foundation │ -│ │ -│ │ -│ Licensed under the Apache License, Version 2.0 (the "License"); you may │ -│ not use this file except in compliance with the License. You may obtain │ -│ a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 │ -│ │ -│ Unless required by applicable law or agreed to in writing, software │ -│ distributed under the License is distributed on an "AS IS" BASIS, │ -│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ -│ See the License for the specific language governing permissions and │ -│ limitations under the License. │ -\*───────────────────────────────────────────────────────────────────────────*/ + │ Copyright (C) 2014 eBay Software Foundation │ + │ │ + │ │ + │ Licensed under the Apache License, Version 2.0 (the "License"); you may │ + │ not use this file except in compliance with the License. You may obtain │ + │ a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 │ + │ │ + │ Unless required by applicable law or agreed to in writing, software │ + │ distributed under the License is distributed on an "AS IS" BASIS, │ + │ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ + │ See the License for the specific language governing permissions and │ + │ limitations under the License. │ + \*───────────────────────────────────────────────────────────────────────────*/ 'use strict'; var async = require('async'), Setup = require('./setup'), - + debug = require('debug'), + log = debug('nemo:log'), + error = debug('nemo:error'), _ = require('lodash'), webdriver = require('selenium-webdriver'); +error.log = console.error.bind(console); + /** * Represents a Nemo instance * @constructor @@ -28,132 +32,136 @@ var async = require('async'), */ function Nemo(config) { - this.nemoData = (config && config.nemoData) ? config.nemoData : undefined, - this.waterFallArray = [], - this.preDriverArray = [], - this.postDriverArray = [], - this.plugins = {}; + log('new Nemo instance created', JSON.stringify(config)); + var nemoData = (config && config.nemoData) ? config.nemoData : undefined, + waterFallArray = [], + preDriverArray = [], + postDriverArray = [], + plugins = {}; //config is for registering plugins if (config && config.plugins) { - this.plugins = config.plugins; + plugins = config.plugins; } -} -Nemo.prototype = { - /** - * - * Nemo.setup - *@param {Object} config - - * { - * 'view': ['example-login', 'serviceError'] //optional - * ,'locator': ['wallet'] //optional - * ,: //optional, depends on plugin setup - * } - *@returns webdriver.promise - successful fulfillment will return an {Object} as below: - * { - * 'view': {} //view instances if specified in config - * ,'locator': {} //locator instances if specified in config - * ,'driver': {} //driver instance. ALWAYS - * ,'wd': {} //static reference to selenium-webdriver. ALWAYS - * ,: //if plugin registers - * } - */ - setup: function(config) { - this.nemoData = (this.nemoData) ? this.nemoData : JSON.parse(process.env.nemoData); - config = config || {}; - var me = this, - nemo = { - 'props': this.nemoData, - 'view': {}, - 'locator': {}, - 'driver': {}, - 'wd': webdriver - }; - var d = webdriver.promise.defer(); - me.preDriverArray = [datasetup]; - Object.keys(me.plugins).forEach(function(key) { - var modulePath, - pluginConfig, - pluginModule; + return { + /** + * + * setup + * @param {Object} config - + * { + * 'view': ['example-login', 'serviceError'] //optional + * ,'locator': ['wallet'] //optional + * ,: //optional, depends on plugin setup + * } + *@returns webdriver.promise - successful fulfillment will return an {Object} as below: + * { + * 'view': {} //view instances if specified in config + * ,'locator': {} //locator instances if specified in config + * ,'driver': {} //driver instance. ALWAYS + * ,'wd': {} //static reference to selenium-webdriver. ALWAYS + * ,: //if plugin registers + * } + */ + setup: function setup(config) { + nemoData = (nemoData) ? nemoData : JSON.parse(process.env.nemoData); + config = config || {}; + var me = this, + nemo = { + 'props': nemoData, + 'view': {}, + 'locator': {}, + 'driver': {}, + 'wd': webdriver + }; + var d = webdriver.promise.defer(); + preDriverArray = [datasetup]; - if ((me.plugins[key].register || config[key]) || key === 'view') { - //register this plugin - pluginConfig = me.plugins[key]; - modulePath = pluginConfig.module; - pluginModule = require(modulePath); - if (me.plugins[key].priority && me.plugins[key].priority < 100) { - me.preDriverArray.push(pluginModule.setup); - } else { - me.postDriverArray.push(pluginModule.setup); + Object.keys(plugins).forEach(function pluginsKeys(key) { + var modulePath, + pluginConfig, + pluginModule; + + if ((plugins[key].register || config[key]) || key === 'view') { + log('register plugin %s', key); + //register this plugin + pluginConfig = plugins[key]; + modulePath = pluginConfig.module; + pluginModule = require(modulePath); + if (plugins[key].priority && plugins[key].priority < 100) { + preDriverArray.push(pluginModule.setup); + } else { + postDriverArray.push(pluginModule.setup); + } } + }); + waterFallArray = preDriverArray.concat([driversetup], postDriverArray); + if (config.view || (plugins && plugins.view)) { + waterFallArray.push(viewsetup); } - }); - me.waterFallArray = me.preDriverArray.concat([driversetup], me.postDriverArray); - if (config.view || (me.plugins && me.plugins.view)) { - me.waterFallArray.push(viewsetup); - } - if (config.locator) { - me.waterFallArray.push(locatorsetup); - } - async.waterfall(me.waterFallArray, function(err, result) { - if (err) { - d.reject(err); - } else { - d.fulfill(nemo); + if (config.locator) { + waterFallArray.push(locatorsetup); } - }); - return d; - - //waterfall functions - function datasetup(callback) { - callback(null, config, nemo); - } - function driversetup(config, _nemo, callback) { - //do driver/view/locator/vars setup - (new Setup()).doSetup(webdriver, _nemo.props, function(err, _nemo) { + async.waterfall(waterFallArray, function waterfall(err, result) { if (err) { - callback(err); + d.reject(err); } else { - //set driver - nemo.driver = _nemo.driver; - callback(null, config, nemo); + d.fulfill(nemo); } }); - } + return d; - function locatorsetup(config, _nemo, callback) { - //setup locators - config.locator.forEach(function(key) { - nemo.locator[key] = require(nemo.props.autoBaseDir + '/locator/' + key); - }); - callback(null, config, nemo); - } - - function viewsetup(config, _nemo, callback) { - var viewModule = _nemo.view; - if (!config.view) { - config.view = []; + //waterfall functions + function datasetup(callback) { + callback(null, config, nemo); } - //setup views - config.view.forEach(function(key) { - if (me.plugins.view) { - //process with the view interface - viewModule.addView(key); - } else { - //old views - //dedupe step - if (nemo.view[key]) { - return; + + function driversetup(config, _nemo, callback) { + //do driver/view/locator/vars setup + (Setup()).doSetup(webdriver, _nemo.props, function setupCallback(err, _nemo) { + if (err) { + callback(err); + } else { + //set driver + nemo.driver = _nemo.driver; + callback(null, config, nemo); } - var viewMod = require(nemo.props.autoBaseDir + '/view/' + key); - nemo.view[key] = new viewMod(_nemo); + }); + } + + function locatorsetup(config, _nemo, callback) { + //setup locators + config.locator.forEach(function (key) { + nemo.locator[key] = require(nemo.props.autoBaseDir + '/locator/' + key); + }); + callback(null, config, nemo); + } + + function viewsetup(config, _nemo, callback) { + var viewModule = _nemo.view; + if (!config.view) { + config.view = []; } + //setup views + config.view.forEach(function viewKeys(key) { + if (plugins.view) { + //process with the view interface + viewModule.addView(key); + } else { + //old views + //dedupe step + if (nemo.view[key]) { + return; + } + var viewMod = require(nemo.props.autoBaseDir + '/view/' + key); + nemo.view[key] = new viewMod(_nemo); + } - }); - callback(null, config, nemo); + }); + callback(null, config, nemo); + } } - } -}; + }; +} module.exports = Nemo; diff --git a/package.json b/package.json index b4b23aa..0c49723 100644 --- a/package.json +++ b/package.json @@ -15,15 +15,16 @@ "main": "index.js", "devDependencies": { "async": "~0.2.8", - "mocha": "~1.10.0", "chai": "~1.6.0", + "debug": "^2.1.0", "grunt": "~0.4.1", - "grunt-simple-mocha": "~0.4.0", - "grunt-loop-mocha": "^0.3.0", "grunt-contrib-jshint": "~0.7.1", + "grunt-loop-mocha": "^0.3.0", + "grunt-simple-mocha": "~0.4.0", + "mocha": "~1.10.0", "nemo-drivex": "^0.1.0", - "nemo-view": "^0.2.0", - "nemo-locatex": "^0.1.0" + "nemo-locatex": "^0.1.0", + "nemo-view": "^0.2.0" }, "repository": { "type": "git", diff --git a/setup/index.js b/setup/index.js index b2c93bf..b6fcb98 100644 --- a/setup/index.js +++ b/setup/index.js @@ -1,87 +1,99 @@ /*───────────────────────────────────────────────────────────────────────────*\ -│ Copyright (C) 2014 eBay Software Foundation │ -│ │ -│ │ -│ Licensed under the Apache License, Version 2.0 (the "License"); you may │ -│ not use this file except in compliance with the License. You may obtain │ -│ a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 │ -│ │ -│ Unless required by applicable law or agreed to in writing, software │ -│ distributed under the License is distributed on an "AS IS" BASIS, │ -│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ -│ See the License for the specific language governing permissions and │ -│ limitations under the License. │ -\*───────────────────────────────────────────────────────────────────────────*/ + │ Copyright (C) 2014 eBay Software Foundation │ + │ │ + │ │ + │ Licensed under the Apache License, Version 2.0 (the "License"); you may │ + │ not use this file except in compliance with the License. You may obtain │ + │ a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 │ + │ │ + │ Unless required by applicable law or agreed to in writing, software │ + │ distributed under the License is distributed on an "AS IS" BASIS, │ + │ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ + │ See the License for the specific language governing permissions and │ + │ limitations under the License. │ + \*───────────────────────────────────────────────────────────────────────────*/ /* global require,module */ 'use strict'; var fs = require('fs'), webdriver = require('selenium-webdriver'), SeleniumServer = require('selenium-webdriver/remote').SeleniumServer, + debug = require('debug'), + log = debug('nemo:log'), + error = debug('nemo:error'), nemoData = {}, driver; -var Setup = function() { - //constructor -}; -Setup.prototype = { - doSetup: function(_wd, nemoData, callback) { - if (nemoData === {} || nemoData.targetBrowser === undefined) { - callback(new Error('[Nemo::doSetup] The nemoData environment variable is missing or not fully defined!')); - return; - } - var caps, - tgtBrowser = nemoData.targetBrowser, - customCaps = nemoData.serverCaps, - serverUrl = nemoData.targetServer, - serverProps = nemoData.serverProps, - serverJar = nemoData.seleniumJar, - errorObject = null; - function getServer() { - if (serverProps && (serverUrl.indexOf('127.0.0.1') !== -1 || serverUrl.indexOf('localhost') !== -1)) { - //chrome and phantomjs are supported natively. i.e. no webdriver required. chromedriver or phantomjs executables must be in PATH though - if (tgtBrowser !== 'chrome' && tgtBrowser !== 'phantomjs') { - //make sure there is a jar file - var jarExists = fs.existsSync(serverJar); - if (!jarExists) { - throw new Error('You must specify a valid SELENIUM_JAR value. The value must point to a driver executable in your file system.'); +error.log = console.error.bind(console); + +function Setup() { + log('new Setup instance created'); + return { + doSetup: function doSetup(_wd, nemoData, callback) { + log('entering doSetup'); + if (nemoData === {} || nemoData.targetBrowser === undefined) { + callback(new Error('[Nemo::doSetup] The nemoData environment variable is missing or not fully defined! Please read about nemoData configuration here: https://github.com/paypal/nemo/blob/master/README.md#nemo-configuration')); + return; + } + var caps, + tgtBrowser = nemoData.targetBrowser, + customCaps = nemoData.serverCaps, + serverUrl = nemoData.targetServer, + serverProps = nemoData.serverProps, + serverJar = nemoData.seleniumJar, + errorObject = null; + + function getServer() { + log('attempt getServer'); + if (serverProps && (serverUrl.indexOf('127.0.0.1') !== -1 || serverUrl.indexOf('localhost') !== -1)) { + log('attempt server startup'); + //chrome and phantomjs are supported natively. i.e. no webdriver required. chromedriver or phantomjs executables must be in PATH though + if (tgtBrowser !== 'chrome' && tgtBrowser !== 'phantomjs') { + //make sure there is a jar file + var jarExists = fs.existsSync(serverJar); + if (!jarExists) { + throw new Error('You must specify a valid SELENIUM_JAR value. The value must point to a driver executable in your file system.'); + } + var server = new SeleniumServer(serverJar, serverProps); + server.start(); + serverUrl = server.address(); + } else { + serverUrl = null; } - var server = new SeleniumServer(serverJar, serverProps); - server.start(); - serverUrl = server.address(); - } else { - serverUrl = null; } + return serverUrl; } - return serverUrl; - } - function getCapabilities() { - //exception handling - if (!webdriver.Capabilities[tgtBrowser]) { - throw new TypeError('You have specified ' + tgtBrowser + ' which is an invalid browser option'); - } - caps = webdriver.Capabilities[tgtBrowser](); + function getCapabilities() { + //specified valid webdriver browser key? + if (!webdriver.Capabilities[tgtBrowser]) { + error('You have specified ' + tgtBrowser + ' which is an invalid webdriver.Capabilities browser option'); - if (customCaps) { - Object.keys(customCaps).forEach(function(key) { - caps.set(key, customCaps[key]); - }); + } else { + caps = webdriver.Capabilities[tgtBrowser](); + } + if (customCaps) { + Object.keys(customCaps).forEach(function customCapsKeys(key) { + caps.set(key, customCaps[key]); + }); + } + + return caps; } - - return caps; - } - try { - driver = new _wd.Builder(). - usingServer(getServer()). - withCapabilities(getCapabilities()).build(); - } catch (err) { - errorObject = err; + try { + + driver = new _wd.Builder(). + usingServer(getServer()). + withCapabilities(getCapabilities()).build(); + } catch (err) { + error('Encountered an error during driver setup: %', err); + errorObject = err; + } + callback(errorObject, { + 'driver': driver + }); } - callback(errorObject, { - 'driver': driver - }); - } -}; + }; +} module.exports = Setup; diff --git a/test/before.js b/test/before.js deleted file mode 100644 index c8af713..0000000 --- a/test/before.js +++ /dev/null @@ -1,12 +0,0 @@ -before(function(done) { - process.env.nemoData = JSON.stringify({ - "autoBaseDir": process.cwd() + "/test", - "targetBrowser": "phantomjs", - //"targetServer": "http://127.0.0.1:4444/wd/hub", - "targetBaseUrl": "https://www.paypal.com", - //"seleniumJar": "/usr/bin/selenium-server-standalone.jar", - //"serverProps": {"port": 4444}, - "locale": "FR" - }); - done(); -}); diff --git a/test/test-setup.js b/test/test-setup.js index 6a10f23..c8e01f9 100644 --- a/test/test-setup.js +++ b/test/test-setup.js @@ -2,26 +2,32 @@ "use strict"; var should = require('chai').should(), - Nemo = require('../index'), - nemo; + Nemo = require('../index'); -describe("nemo setup", function() { +describe("nemo functionality", function () { var driver; + var nemo; var config = require("./config/plugins"); - var _nemo = new Nemo(config); + config.nemoData = { + "autoBaseDir": process.cwd() + "/test", + "targetBrowser": "phantomjs", + "targetBaseUrl": "http://localhost:8000", + "locale": "FR" + }; + var _nemo = Nemo(config); - after(function(done) { - driver.quit().then(function() { + after(function (done) { + driver.quit().then(function () { done(); }); }); - it("should create a new instance", function(done) { + it("should create a new instance", function (done) { _nemo.should.not.equal(undefined); done(); }); - it("should return back camelcase properties from titlecase ARGV options and also init any plugins", function(done) { + it("should return back camelcase properties from titlecase ARGV options and also init any plugins", function (done) { //console.log(_nemo.setup); - var su = _nemo.setup({ + _nemo.setup({ "samplePlugin": { "sampleoptions": { "option1": "value1", @@ -30,65 +36,60 @@ describe("nemo setup", function() { }, "locator": ["myView"], "view": ["myView", "myOtherView"] - }); - //console.log(su) - su.then(function(result) { + }).then(function (result) { nemo = result; nemo.props.targetBrowser.should.equal("phantomjs"); - //nemo.props.targetServer.should.equal("http://127.0.0.1:4444/wd/hub"); - nemo.props.targetBaseUrl.should.equal("https://www.paypal.com"); - //nemo.noValue.should.equal(true); + nemo.props.targetBaseUrl.should.equal("http://localhost:8000"); nemo.samplePlugin.sampleoptions.option1.should.equal("value1"); - //nemo.autoRegPlugin.should.exist(); driver = nemo.driver; done(); - }, function(err) { + }, function (err) { done(err); }); }); - it("should navigate to the TARGET_BASE_URL set via command line", function(done) { + it("should navigate to the TARGET_BASE_URL set via command line", function (done) { driver.get(nemo.props.targetBaseUrl). - then(function() { - done(); - }, function(err) { - done(err); - }); + then(function () { + done(); + }, function (err) { + done(err); + }); }); - it("should register plugin with priority < 100 prior to driver setup", function() { + it("should register plugin with priority < 100 prior to driver setup", function () { nemo.samplePlugin.isDriverSetup.should.equal(false); return true; }); - it("should take props values from plugin registration", function() { + it("should take props values from plugin registration", function () { nemo.props.fromSamplePlugin.should.equal(true); return true; }); - it("should register plugin with no priority after driver setup", function() { + it("should register plugin with no priority after driver setup", function () { nemo.autoRegPlugin.isDriverSetup.should.equal(true); return true; }); - describe("nemo.locator", function() { - it("should have pulled in the myView locator", function(done) { + describe("nemo.locator", function () { + it("should have pulled in the myView locator", function (done) { if (!nemo.locator.myView) { done(new Error("didn't get the locator")); } else { done(); } }); - it("should get the FR locator when locale is FR", function(done) { + it("should get the FR locator when locale is FR", function (done) { if (nemo.props.locale === "FR" && nemo.locatex("myView.cityOption").locator === "select[name='ddlTown'] option[value='Burkino Faso']") { done(); } else { done(new Error("didn't get an FR flavored locator")); } }); - it("should get the default locator when locale is FR and no FR locator", function(done) { + it("should get the default locator when locale is FR and no FR locator", function (done) { if (nemo.props.locale === "FR" && nemo.locatex("myView.noFRyesDefault").locator === "defaultId") { done(); } else { done(new Error("didn't get an default flavored locator")); } }); - it("should get the single locator when no locale-specific or default locator", function(done) { + it("should get the single locator when no locale-specific or default locator", function (done) { if (nemo.props.locale === "FR" && nemo.locatex("myView.noFRnoDefault").locator === "onlyId") { done(); } else { @@ -96,52 +97,32 @@ describe("nemo setup", function() { } }); }); - describe("nemo.view", function() { - it("should have the view methods available", function(done) { + describe("nemo.view", function () { + it("should have the view methods available", function (done) { if (nemo.view.myView && nemo.view.myView.fname && nemo.view.myView.fname.constructor === Function) { done(); } else { done(new Error("didn't get the view method")); } }); - it("should use the view methods", function(done) { - nemo.driver.get("https://edit.yahoo.com/registration"); + it("should use the view methods", function (done) { + //nemo.driver.get("https://edit.yahoo.com/registration"); + nemo.driver.get("http://localhost:8000"); nemo.view.myView.fnameWait(3000). - then(function(present) { - if (present) { - nemo.view.myView.fname().sendKeys("asdf"); - } else { - console.log('fname not present'); - } - }). - then(function() { - driver.sleep(4000); - }). - then(function() { - done(); - }); + then(function (present) { + if (present) { + nemo.view.myView.fname().sendKeys("asdf"); + } else { + console.log('fname not present'); + } + }). + then(function () { + driver.sleep(4000); + }). + then(function () { + done(); + }); }); - // it("should use the view and subview interface methods", function (done) { - // nemo.driver.get("http://accessify.com/features/tutorials/accessible-forms/form-examples.htm"); - // nemo.view.myView.cityOptionPresent(). - // then(function (present) { - // nemo.view.myView.cityOption().click(); - // }). - // then(function () { - // driver.sleep(4000); - // }). - // then(function () { - // done(); - // }); - // }); - // it("should use the view and subview methods", function (done) { - // nemo.view.myView.tellLifeStory(). - // then(function () { - // done(); - // }, function (err) { - // //console.log("D'oh'eth"); - // done(err); - // }); - // }); + }); -}); \ No newline at end of file +});