diff --git a/docs/referenceConf.js b/docs/referenceConf.js index cacb00b6f..3e4399f8b 100644 --- a/docs/referenceConf.js +++ b/docs/referenceConf.js @@ -21,7 +21,8 @@ exports.config = { // running. // 3. sauceUser/sauceKey - to use remote Selenium Servers via Sauce Labs. // 4. browserstackUser/browserstackKey - to use remote Selenium Servers via BrowserStack. - // 5. directConnect - to connect directly to the browser Drivers. + // 5. testingbotKey/testingbotSecret - to use remote Selenium Servers via TestingBot. + // 6. directConnect - to connect directly to the browser Drivers. // This option is only available for Firefox and Chrome. // ---- 1. To start a standalone Selenium Server locally --------------------- @@ -86,7 +87,13 @@ exports.config = { browserstackUser: null, browserstackKey: null, - // ---- 5. To connect directly to Drivers ------------------------------------ + // ---- 5. To use remote browsers via TestingBot --------------------------- + // If testingbotKey and testingbotSecret are specified, seleniumServerJar will be ignored. + // The tests will be run remotely using TestingBot. + testingbotKey: null, + testingbotSecret: null, + + // ---- 6. To connect directly to Drivers ------------------------------------ // Boolean. If true, Protractor will connect directly to the browser Drivers // at the locations specified by chromeDriver and firefoxPath. Only Chrome // and Firefox are supported for direct connect. @@ -144,7 +151,7 @@ exports.config = { // Name of the process executing this capability. Not used directly by // protractor or the browser, but instead pass directly to third parties - // like BrowserStack and SauceLabs as the name of the job running this test + // like BrowserStack, SauceLabs and TestingBot as the name of the job running this test name: 'Unnamed Job', // User defined name for the capability that will display in the results log @@ -178,6 +185,7 @@ exports.config = { // specified here. // For a list of BrowserStack specific capabilities, visit // https://www.browserstack.com/automate/capabilities + // or for TestingBot: https://testingbot.com/support/other/test-options }, // If you would like to run more than one instance of WebDriver on the same diff --git a/docs/server-setup.md b/docs/server-setup.md index ffac30823..a42eba3a8 100644 --- a/docs/server-setup.md +++ b/docs/server-setup.md @@ -55,13 +55,13 @@ To connect to a running instance of a standalone Selenium Server, set this optio - `seleniumAddress` - Connect to a running instance of a standalone Selenium Server. The address will be a URL. -Please note that if you set seleniumAddress, the settings for `seleniumServerJar`, `seleniumPort`, `seleniumArgs`, `browserstackUser`, `browserstackKey`, `sauceUser` and `sauceKey` will be ignored. +Please note that if you set seleniumAddress, the settings for `seleniumServerJar`, `seleniumPort`, `seleniumArgs`, `browserstackUser`, `browserstackKey`, `testingbotKey`, `testingbotSecret`, `sauceUser` and `sauceKey` will be ignored. Remote Selenium Server ---------------------- -To run your tests against a remote Selenium Server, you will need an account with a service that hosts the server (and the browser drivers). Protractor has built in support for [BrowserStack](https://www.browserstack.com) and [Sauce Labs](http://www.saucelabs.com). +To run your tests against a remote Selenium Server, you will need an account with a service that hosts the server (and the browser drivers). Protractor has built in support for [BrowserStack](https://www.browserstack.com), [TestingBot](https://testingbot.com) and [Sauce Labs](http://www.saucelabs.com). **Using BrowserStack as remote Selenium Server** @@ -83,6 +83,16 @@ Please note that if you set `sauceUser` and `sauceKey`, the settings for `seleni You can optionally set the [`name` property](referenceConf.js#L121) in a capability in order to give the jobs a name on the server. Otherwise they will just be called `Unnamed Job`. +**Using TestingBot as remote Selenium Server** + +In your config file, set these options: + - `testingbotKey` - The key for your TestingBot account. + - `testingbotSecret` - The secret for your TestingBot account. + +Please note that if you set `testingbotKey` and `testingbotSecret`, the settings for `seleniumServerJar`, `seleniumPort`, `seleniumArgs`, `browserstackUser` and `browserstackKey`, `sauceUser` and `sauceKey` will be ignored. + +You can optionally set the [`name` property](referenceConf.js#L121) in a capability in order to give the jobs a name on the server. Otherwise they will just be allotted a random hash. + Connecting Directly to Browser Drivers -------------------------------------- diff --git a/lib/driverProviders/testingbot.js b/lib/driverProviders/testingbot.js new file mode 100644 index 000000000..5744c57d8 --- /dev/null +++ b/lib/driverProviders/testingbot.js @@ -0,0 +1,90 @@ +/* + * This is an implementation of the TestingBot Driver Provider. + * It is responsible for setting up the account object, tearing + * it down, and setting up the driver correctly. + */ + +var util = require('util'), + log = require('../logger'), + TestingBot = require('testingbot-api'), + crypto = require('crypto'), + q = require('q'), + DriverProvider = require('./driverProvider'); + + +var TestingBotDriverProvider = function(config) { + DriverProvider.call(this, config); + this.tbServer_ = {}; +}; +util.inherits(TestingBotDriverProvider, DriverProvider); + + +/** + * Hook to update the TestingBot job. + * @public + * @param {Object} update + * @return {q.promise} A promise that will resolve when the update is complete. + */ +TestingBotDriverProvider.prototype.updateJob = function(update) { + var self = this; + var deferredArray = this.drivers_.map(function(driver) { + var deferred = q.defer(); + driver.getSession().then(function(session) { + var hash = crypto.createHash('md5'); + var auth = hash.update(self.config_.testingbotKey + ':' + + self.config_.testingbotSecret + ':' + session.getId()).digest('hex'); + log.puts('TestingBot results available at http://testingbot.com/tests/' + + session.getId() + '?auth=' + auth); + var apiSend = { + 'test[success]' : update.passed ? 1 : 0 + }; + self.tbServer_.updateTest(apiSend, session.getId(), function(err) { + if (err) { + throw new Error( + 'Error updating TestingBot pass/fail status: ' + util.inspect(err) + ); + } + deferred.resolve(); + }); + }); + return deferred.promise; + }); + return q.all(deferredArray); +}; + +/** + * Configure and launch (if applicable) the object's environment. + * @public + * @return {q.promise} A promise which will resolve when the environment is + * ready to test. + */ +TestingBotDriverProvider.prototype.setupEnv = function() { + var deferred = q.defer(); + this.tbServer_ = new TestingBot({ + api_key: this.config_.testingbotKey, + api_secret: this.config_.testingbotSecret + }); + this.config_.capabilities.username = this.config_.testingbotKey; + this.config_.capabilities.accessKey = this.config_.testingbotSecret; + var auth = 'http://' + this.config_.testingbotKey + ':' + + this.config_.testingbotSecret + '@'; + this.config_.seleniumAddress = auth + + 'hub.testingbot.com:80/wd/hub'; + + // Append filename to capabilities.name so that it's easier to identify tests. + if (this.config_.capabilities.name && + this.config_.capabilities.shardTestFiles) { + this.config_.capabilities.name += ( + ':' + this.config_.specs.toString().replace(/^.*[\\\/]/, '')); + } + + log.puts('Using TestingBot selenium server at ' + + this.config_.seleniumAddress.replace(/\/\/.+@/, '//')); + deferred.resolve(); + return deferred.promise; +}; + +// new instance w/ each include +module.exports = function(config) { + return new TestingBotDriverProvider(config); +}; diff --git a/package.json b/package.json index eab18d348..2a6281894 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "request": "~2.67.0", "saucelabs": "~1.0.1", "selenium-webdriver": "2.53.2", - "source-map-support": "~0.4.0" + "source-map-support": "~0.4.0", + "testingbot-api": "~1.0.1" }, "devDependencies": { "body-parser": "1.14.2",