Skip to content

Commit

Permalink
feat(config): require config as a regular module
Browse files Browse the repository at this point in the history
Closes #304

BREAKING CHANGE: Update your karma.conf.js to export a config function.
````javascript
module.exports = function(karma) {
  karma.configure({
    autoWatch: true,
    // ...
  });
};
  • Loading branch information
pavelgj authored and vojtajina committed Apr 18, 2013
1 parent 4b98c4c commit a37fd6f
Show file tree
Hide file tree
Showing 20 changed files with 565 additions and 523 deletions.
2 changes: 1 addition & 1 deletion Gruntfile.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ module.exports = (grunt) ->
unit: 'simplemocha:unit'
tasks: 'simplemocha:tasks'
client: 'test/client/karma.conf.js'
e2e: 'test/e2e/*/karma.conf.js'
e2e: ['test/e2e/*/karma.conf.js', 'test/e2e/*/karma.conf.coffee']


simplemocha:
Expand Down
92 changes: 48 additions & 44 deletions config.template
Original file line number Diff line number Diff line change
@@ -1,74 +1,78 @@
// Karma configuration
// Generated on %DATE%

module.exports = function(karma) {
karma.configure({

// base path, that will be used to resolve files and exclude
basePath = '%BASE_PATH%';
// base path, that will be used to resolve files and exclude
basePath: '%BASE_PATH%',


// frameworks to use
frameworks = [%FRAMEWORKS%];
// frameworks to use
frameworks: [%FRAMEWORKS%],


// list of files / patterns to load in the browser
files = [
%FILES%
];
// list of files / patterns to load in the browser
files: [
%FILES%
],


// list of files to exclude
exclude = [
%EXCLUDE%
];
// list of files to exclude
exclude: [
%EXCLUDE%
],


// test results reporter to use
// possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
reporters = ['progress'];
// test results reporter to use
// possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
reporters: ['progress'],


// web server port
port = 9876;
// web server port
port: 9876,


// cli runner port
runnerPort = 9100;
// cli runner port
runnerPort: 9100,


// enable / disable colors in the output (reporters and logs)
colors = true;
// enable / disable colors in the output (reporters and logs)
colors: true,


// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel = LOG_INFO;
// level of logging
// possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
logLevel: karma.LOG_INFO,


// enable / disable watching file and executing tests whenever any file changes
autoWatch = %AUTO_WATCH%;
// enable / disable watching file and executing tests whenever any file changes
autoWatch: %AUTO_WATCH%,


// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers = [%BROWSERS%];
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: [%BROWSERS%],


// If browser does not capture in given timeout [ms], kill it
captureTimeout = 60000;
// If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000,


// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun = false;
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false,


// plugins to load
plugins = [
%PLUGINS%
];
// plugins to load
plugins: [
%PLUGINS%
],
});
};
136 changes: 57 additions & 79 deletions lib/config.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
var fs = require('fs');
var path = require('path');
var vm = require('vm');
var coffee = require('coffee-script');

var log = require('./logger').create('config');
var helper = require('./helper');
var constant = require('./constants');

// Coffee is required here to enable config files written in coffee-script.
// It's not directly used in this file.
require('coffee-script');


var Pattern = function(pattern, served, included, watched) {
this.pattern = pattern;
Expand Down Expand Up @@ -39,8 +40,7 @@ var createPatternObject = function(pattern) {
return new Pattern(null, false, false, false);
};


var normalizeConfig = function(config) {
var normalizeConfig = function(config, configFilePath) {

var basePathResolve = function(relativePath) {
if (helper.isUrlAbsolute(relativePath)) {
Expand All @@ -61,6 +61,16 @@ var normalizeConfig = function(config) {
};
};

if (helper.isString(configFilePath)) {
// resolve basePath
config.basePath = path.resolve(path.dirname(configFilePath), config.basePath);

// always ignore the config file itself
config.exclude.push(configFilePath);
} else {
config.basePath = path.resolve(config.basePath || '.');
}

config.files = config.files.map(createPatternObject).map(createPatternMapper(basePathResolve));
config.exclude = config.exclude.map(basePathResolve);
config.junitReporter.outputFile = basePathResolve(config.junitReporter.outputFile);
Expand Down Expand Up @@ -121,85 +131,64 @@ var normalizeConfig = function(config) {
return config;
};


var readConfigFile = function(filepath) {
var configEnv = {
// constants
LOG_DISABLE: constant.LOG_DISABLE,
LOG_ERROR: constant.LOG_ERROR,
LOG_WARN: constant.LOG_WARN,
LOG_INFO: constant.LOG_INFO,
LOG_DEBUG: constant.LOG_DEBUG,
// access to globals
console: console,
require: require,
process: process,
__filename: filepath,
__dirname: path.dirname(filepath)
};

var KarmaDsl = function(config) {
this.LOG_DISABLE = constant.LOG_DISABLE;
this.LOG_ERROR = constant.LOG_ERROR;
this.LOG_WARN = constant.LOG_WARN;
this.LOG_INFO = constant.LOG_INFO;
this.LOG_DEBUG = constant.LOG_DEBUG;

// TODO(vojta): remove
var CONST_ERR = '%s is not supported anymore.\n\tPlease use `frameworks = ["%s"];` instead.';
['JASMINE', 'MOCHA', 'QUNIT'].forEach(function(framework) {
[framework, framework + '_ADAPTER'].forEach(function(name) {
Object.defineProperty(configEnv, name, {get: function() {
Object.defineProperty(global, name, {get: function() {
log.warn(CONST_ERR, name, framework.toLowerCase());
}});
});
});

['REQUIRE', 'REQUIRE_ADAPTER'].forEach(function(name) {
Object.defineProperty(configEnv, name, {get: function() {
Object.defineProperty(global, name, {get: function() {
log.warn(CONST_ERR, name, 'requirejs');
}});
});

['ANGULAR_SCENARIO', 'ANGULAR_SCENARIO_ADAPTER'].forEach(function(name) {
Object.defineProperty(configEnv, name, {get: function() {
Object.defineProperty(global, name, {get: function() {
log.warn(CONST_ERR, name, 'requirejs');
}});
});

var configSrc;
try {
configSrc = fs.readFileSync(filepath);
} catch(e) {
if (e.code === 'ENOENT' || e.code === 'EISDIR') {
log.error('Config file does not exist!');
} else {
log.error('Unexpected error opening config file!\n', e);
}

process.exit(1);
}
this.configure = function(newConfig) {
Object.keys(newConfig).forEach(function(key) {
config[key] = newConfig[key];
});
};
};

try {
// if the configuration file is coffeescript compile it
if (path.extname(filepath) === '.coffee') {
configSrc = coffee.compile(configSrc.toString(), {bare: true});
var parseConfig = function(configFilePath, cliOptions) {
var configModule;
if (configFilePath) {
try {
configModule = require(configFilePath);
} catch(e) {
if (e.code === 'MODULE_NOT_FOUND') {
log.error('Config file does not exist!');
} else {
log.error('Invalid config file!\n', e);
}
return process.exit(1);
}

vm.runInNewContext(configSrc, configEnv);
} catch(e) {
if (e.name === 'SyntaxError') {
log.error('Syntax error in config file!\n' + e.message);
} else {
log.error('Invalid config file!\n', e);
if (!helper.isFunction(configModule)) {
log.error('Config file must export a function!');
return process.exit(1);
}

process.exit(1);
} else {
// if no config file path is passed, we define a dummy config module.
configModule = function() {};
}

return configEnv;
};


var parseConfig = function(configFilePath, cliOptions) {

var configFromFile = helper.isString(configFilePath) ? readConfigFile(configFilePath) : {};

// default config
var config = {
frameworks: [],
port: constant.DEFAULT_PORT,
Expand Down Expand Up @@ -237,31 +226,20 @@ var parseConfig = function(configFilePath, cliOptions) {
'karma-coffee-preprocessor'
]
};
var dsl = new KarmaDsl(config);
try {
configModule(dsl);
} catch(e) {
log.error('Error in config file!\n', e);
return process.exit(1);
}

// merge the config from config file and cliOptions (precendense)
Object.getOwnPropertyNames(config).forEach(function(key) {
if (cliOptions.hasOwnProperty(key)) {
config[key] = cliOptions[key];
} else if (configFromFile.hasOwnProperty(key)) {
config[key] = configFromFile[key];
}
});

if (helper.isString(configFilePath)) {
// resolve basePath
config.basePath = path.resolve(path.dirname(configFilePath), config.basePath);
dsl.configure(cliOptions);

// always ignore the config file itself
config.exclude.push(configFilePath);
}
else {
config.basePath = path.resolve(config.basePath);
}

return normalizeConfig(config);
return normalizeConfig(config, configFilePath);
};


// PUBLIC API
exports.parseConfig = parseConfig;
exports.Pattern = Pattern;
Expand Down
Loading

0 comments on commit a37fd6f

Please sign in to comment.