Skip to content
This repository was archived by the owner on Jul 29, 2024. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 4 additions & 35 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ try {

var util = require('util');
var path = require('path');
var runner = require('./runner.js');
var child = require('child_process');
var argv = require('optimist').
usage('Usage: protractor [options] [configFile]\n' +
'The [options] object will override values from the config file.\n' +
Expand Down Expand Up @@ -67,22 +67,6 @@ if (argv.version) {
process.exit(0);
}


// Any file names should be resolved relative to the current working directory.
var processFilePatterns = function(list) {
var patterns = list.split(',');
patterns.forEach(function(spec, index, arr) {
arr[index] = path.resolve(process.cwd(), spec);
});
return patterns;
}
if (argv.specs) {
argv.specs = processFilePatterns(argv.specs);
}
if (argv.exclude) {
argv.exclude = processFilePatterns(argv.exclude);
}

// WebDriver capabilities properties require dot notation.
var flattenObject = function(obj) {
var prefix = arguments[1] || '';
Expand All @@ -93,26 +77,11 @@ var flattenObject = function(obj) {
}
}
return out;
}
};

if (argv.capabilities) {
argv.capabilities = flattenObject(argv.capabilities);
}

['seleniumServerJar', 'chromeDriver', 'onPrepare'].forEach(function(name) {
if (argv[name]) {
argv[name] = path.resolve(process.cwd(), argv[name]);
}
});

var configFilename = argv._[0];
if (configFilename) {
var configPath = path.resolve(process.cwd(), configFilename);
var config = require(configPath).config;
config.configDir = path.dirname(configPath);
runner.addConfig(config);
}

runner.addConfig(argv);

runner.runOnce();
// Run the launcher
require('./launcher').init(argv);
239 changes: 239 additions & 0 deletions lib/configParser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
var path = require('path'),
glob = require('glob'),
config_ = {
configDir: './',
jasmineNodeOpts: {}
},
//this allows for ease of maintaining public apis of the config while still
// allowing for easy variable renames or future config api changes while
// supported backwards compatibility
configMap_ = {

//structure is internal name -> supported config apis
'specs': ['specs'],
'exclude': ['exclude'],
'capabilities': ['capabilities'],
'seleniumHost': ['seleniumAddress'],
'rootElement': ['rootElement'],
'baseUrl': ['baseUrl'],
'timeout': ['allScriptsTimeout'],
'browserParams': ['params'],
'framework': ['framework'],
'jasmineOpts': ['jasmineNodeOpts'],
'mochaOpts': ['mochaOpts'],
'seleniumLocal.jar': ['seleniumServerJar'],
'seleniumLocal.args': ['seleniumArgs'],
'seleniumLocal.port': ['seleniumPort'],
'sauceAccount.user': ['sauceUser'],
'sauceAccount.key': ['sauceKey'],
'chromeDriver': ['chromeDriver'],
'chromeOnly': ['chromeOnly'],
'configDir': ['configDir'],
'cucumberOpts.require': ['cucumberOpts.require'],
'cucumberOpts.format': ['cucumberOpts.format'],
'cucumberOpts.tags': ['cucumberOpts.tags']
};

/**
* Merge config objects together.
*
* @private
* @param {Object} into
* @param {Object} from
*
* @return {Object} The 'into' config.
*/
var merge_ = function(into, from) {
for (var key in from) {
if (into[key] instanceof Object && !(into[key] instanceof Array)) {
merge_(into[key], from[key]);
} else {
into[key] = from[key];
}
}
return into;
};

/**
* Resolve a list of file patterns into a list of individual file paths.
*
* @param {Array/String} patterns
* @param {Boolean} opt_omitWarnings whether to omit did not match warnings
*
* @return {Array} The resolved file paths.
*/
var resolveFilePatterns = function(patterns, opt_omitWarnings) {
var resolvedFiles = [];

patterns = (typeof patterns === 'string') ?
[patterns] : patterns;

if (patterns) {
for (var i = 0; i < patterns.length; ++i) {
var matches = glob.sync(patterns[i], {cwd: config_.configDir});
if (!matches.length && !opt_omitWarnings) {
util.puts('Warning: pattern ' + patterns[i] + ' did not match any files.');
}
for (var j = 0; j < matches.length; ++j) {
resolvedFiles.push(path.resolve(config_.configDir, matches[j]));
}
}
}
return resolvedFiles;
};

/**
* Helper to resolve file pattern strings relative to the cwd
*
* @private
* @param {Array} list
*/
var processFilePatterns_ = function(list) {
var patterns = list.split(',');
patterns.forEach(function(spec, index, arr) {
arr[index] = path.resolve(process.cwd(), spec);
});
return patterns;
};

/**
* Add the options in the parameter config to this runner instance.
*
* @private
* @param {Object} additionalConfig
*/
var addConfig_ = function(additionalConfig) {
// All filepaths should be kept relative to the current config location.
// This will not affect absolute paths.
['seleniumServerJar', 'chromeDriver', 'onPrepare'].forEach(function(name) {
if (additionalConfig[name] && additionalConfig.configDir &&
typeof additionalConfig[name] === 'string') {
additionalConfig[name] =
path.resolve(additionalConfig.configDir, additionalConfig[name]);
}
});

// Make sure they're not trying to add in deprecated config vals
if (additionalConfig.jasmineNodeOpts &&
additionalConfig.jasmineNodeOpts.specFolders) {
throw new Error('Using config.jasmineNodeOpts.specFolders is deprecated ' +
'since Protractor 0.6.0. Please switch to config.specs.');
}
merge_(config_,additionalConfig);
};


/**
* Merges in passed in configuration data with existing class defaults
* @public
* @param {Object} config - A set of properties collected that will be merged
* with AbstractTestRunner defaults
*/
var loadConfig = function(configObj, configToLoad) {

if (!configToLoad || !configObj) {
return;
}

/* helper to set the correct value for string dot notation */
function setConfig_(obj, str, val) {
str = str.split('.');
while (str.length > 1) {
obj = obj[str.shift()];
}
obj[str.shift()] = val;
}

/* helper to retrieve the correct value for string dot notation */
function getConfig_(obj, str) {
var arr = str.split(".");
while(arr.length && (obj = obj[arr.shift()]));
return obj;
}

/* helper to determine whether a config value is empty based on type */
function isEmpty_(val) {
return ( val !== null &&
val !== '' &&
val !== undefined &&
!(val instanceof Array &&
!val.length) &&
!(val instanceof Object &&
!Object.keys(val).length)
);
}

//object definition driven merging
var key,configDef,configAlias,i;
for (key in configMap_) {

configDef = configMap_[key];
for (i=0; i<configDef.length; i++) {
configAlias = configDef[i];
var configVal = getConfig_(configToLoad,configAlias);
if (isEmpty_(configVal)) {
//override config default w/ passed in config
setConfig_(configObj,key,configVal);
}
}
}
};




/**
* Public function specialized towards merging in a file's config
*
* @public
* @param {String} filename
*/
var addFileConfig = function(filename) {
if (!filename) {
return;
}
var filePath = path.resolve(process.cwd(), filename);
var fileConfig = require(filePath).config;
fileConfig.configDir = path.dirname(filePath);
addConfig_(fileConfig);
};


/**
* Public function specialized towards merging in config from argv
*
* @public
* @param {Object} argv
*/
var addArgvConfig = function(argv) {
if (!argv) {
return;
}
// Interpret/parse spec include/exclude patterns
if (argv.specs) {
argv.specs = processFilePatterns_(argv.specs);
}
if (argv.exclude) {
argv.exclude = processFilePatterns(argv.exclude);
}

addConfig_(argv);
};


/**
* Public getter for the final, computed config object
*
* @public
* @return {Object} config
*/
var getConfig = function() {
return config_;
};


exports.addArgvConfig = addArgvConfig;
exports.addFileConfig = addFileConfig;
exports.getConfig = getConfig;
exports.loadConfig = loadConfig;
exports.resolveFilePatterns = resolveFilePatterns;
64 changes: 64 additions & 0 deletions lib/driverProviders/chrome.dp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* This is an implementation of the Chrome Driver Provider.
* It is responsible for setting up the account object, tearing
* it down, and setting up the driver correctly.
*/

var util = require('util'),
webdriver = require('selenium-webdriver'),
chrome = require('selenium-webdriver/chrome'),
q = require('q');

function ChromeDriverProvider(testRunner) {

this.testRunner_ = testRunner;
this.trConfig_ = this.testRunner_.getConfig();
this.driver_ = null;
}

/**
* setupEnv is responsible for configuring and launching (if applicable)
* the object's environment.
* @public
* @return promise
*/
ChromeDriverProvider.prototype.setupEnv = function() {
var deferred = q.defer();
util.puts('Using ChromeDriver directly...');
deferred.resolve();
return deferred.promise;
};

/**
* teardownEnv is responsible for destroying the environment and doing any
* associated cleanup.
* @public
* @param {runnerResult} runner
*/
ChromeDriverProvider.prototype.teardownEnv = function(runner) {
var deferred = q.defer(),
passed = runner.results().failedCount === 0,
exitCode = passed ? 0 : 1;

deferred.resolve(exitCode);
return deferred.promise;
};

/**
* getDriver is responsible for retrieving the webdriver for the runner.
* @public
* @return webdriver instance
*/
ChromeDriverProvider.prototype.getDriver = function() {
if (!this.driver_) {
var service = new chrome.ServiceBuilder(this.trConfig_.chromeDriver).build();
this.driver_ = chrome.createDriver(
new webdriver.Capabilities(this.trConfig_.capabilities), service);
}
return this.driver_;
};

//new instance w/ each include
module.exports = (function(testRunner) {
return new ChromeDriverProvider(testRunner);
});
Loading