From fca930e3a5a4d27c9ca9ff595e0b4aab3df4b590 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Thu, 6 Nov 2014 19:31:06 -0800 Subject: [PATCH 01/11] feat: Fail on launcher-, reporter-, plugin-, or preprocessor-load errors. Stop karma if a launcher, reporter, plugin, or preprocessor fails to load, after attempting to load each of them, and reporting errors for each load error. Closes #855 --- lib/launcher.js | 18 ++++-- lib/plugin.js | 38 ++++++------ lib/preprocessor.js | 23 +++---- lib/reporter.js | 5 +- lib/server.js | 20 ++++++- test/e2e/load.feature | 106 +++++++++++++++++++++++++++++++++ test/unit/launcher.spec.js | 17 +++++- test/unit/preprocessor.spec.js | 29 ++++----- 8 files changed, 203 insertions(+), 53 deletions(-) create mode 100644 test/e2e/load.feature diff --git a/lib/launcher.js b/lib/launcher.js index 988133176..0d32b1157 100644 --- a/lib/launcher.js +++ b/lib/launcher.js @@ -10,8 +10,12 @@ var retryDecorator = require('./launchers/retry').decoratorFactory var processDecorator = require('./launchers/process').decoratorFactory // TODO(vojta): remove once nobody uses it -var baseBrowserDecoratorFactory = function (baseLauncherDecorator, captureTimeoutLauncherDecorator, - retryLauncherDecorator, processLauncherDecorator) { +var baseBrowserDecoratorFactory = function ( + baseLauncherDecorator, + captureTimeoutLauncherDecorator, + retryLauncherDecorator, + processLauncherDecorator +) { return function (launcher) { baseLauncherDecorator(launcher) captureTimeoutLauncherDecorator(launcher) @@ -20,7 +24,7 @@ var baseBrowserDecoratorFactory = function (baseLauncherDecorator, captureTimeou } } -var Launcher = function (emitter, injector) { +var Launcher = function (server, emitter, injector) { var browsers = [] var lastStartTime @@ -61,15 +65,17 @@ var Launcher = function (emitter, injector) { var browser = injector.createChild([locals], ['launcher:' + name]).get('launcher:' + name) } catch (e) { if (e.message.indexOf('No provider for "launcher:' + name + '"') !== -1) { - log.warn('Can not load "%s", it is not registered!\n ' + + log.error('Cannot load browser "%s": it is not registered! ' + 'Perhaps you are missing some plugin?', name) } else { - log.warn('Can not load "%s"!\n ' + e.stack, name) + log.error('Cannot load browser "%s"!\n ' + e.stack, name) } + emitter.emit('load_error', 'launcher', name) return } + if (server.loadErrors.length > 0) return [] // TODO(vojta): remove in v1.0 (BC for old launchers) if (!browser.forceKill) { browser.forceKill = function () { @@ -193,7 +199,7 @@ var Launcher = function (emitter, injector) { emitter.on('exit', this.killAll) } -Launcher.$inject = ['emitter', 'injector'] +Launcher.$inject = ['server', 'emitter', 'injector'] Launcher.generateId = function () { return '' + Math.floor(Math.random() * 100000000) diff --git a/lib/plugin.js b/lib/plugin.js index a68e6d62d..cfc60e35f 100644 --- a/lib/plugin.js +++ b/lib/plugin.js @@ -6,7 +6,7 @@ var log = require('./logger').create('plugin') var IGNORED_PACKAGES = ['karma-cli', 'karma-runner.github.com'] -exports.resolve = function (plugins) { +exports.resolve = function (plugins, emitter) { var modules = [] var requirePlugin = function (name) { @@ -15,35 +15,39 @@ exports.resolve = function (plugins) { modules.push(require(name)) } catch (e) { if (e.code === 'MODULE_NOT_FOUND' && e.message.indexOf(name) !== -1) { - log.warn('Cannot find plugin "%s".\n Did you forget to install it ?\n' + + log.error('Cannot find plugin "%s".\n Did you forget to install it?\n' + ' npm install %s --save-dev', name, name) } else { - log.warn('Error during loading "%s" plugin:\n %s', name, e.message) + log.error('Error during loading "%s" plugin:\n %s', name, e.message) } + emitter.emit('load_error', 'plug_in', name) } } plugins.forEach(function (plugin) { if (helper.isString(plugin)) { - if (plugin.indexOf('*') !== -1) { - var pluginDirectory = path.normalize(path.join(__dirname, '/../..')) - var regexp = new RegExp('^' + plugin.replace('*', '.*')) - - log.debug('Loading %s from %s', plugin, pluginDirectory) - fs.readdirSync(pluginDirectory).filter(function (pluginName) { - return IGNORED_PACKAGES.indexOf(pluginName) === -1 && regexp.test(pluginName) - }).forEach(function (pluginName) { - requirePlugin(pluginDirectory + '/' + pluginName) - }) - } else { + if (plugin.indexOf('*') === -1) { requirePlugin(plugin) + return } - } else if (helper.isObject(plugin)) { + var pluginDirectory = path.normalize(path.join(__dirname, '/../..')) + var regexp = new RegExp('^' + plugin.replace('*', '.*')) + + log.debug('Loading %s from %s', plugin, pluginDirectory) + fs.readdirSync(pluginDirectory).filter(function (pluginName) { + return IGNORED_PACKAGES.indexOf(pluginName) === -1 && regexp.test(pluginName) + }).forEach(function (pluginName) { + requirePlugin(pluginDirectory + '/' + pluginName) + }) + return + } + if (helper.isObject(plugin)) { log.debug('Loading inlined plugin (defining %s).', Object.keys(plugin).join(', ')) modules.push(plugin) - } else { - log.warn('Invalid plugin %s', plugin) + return } + log.error('Invalid plugin %s', plugin) + emitter.emit('load_error', 'plug_in', plugin) }) return modules diff --git a/lib/preprocessor.js b/lib/preprocessor.js index 2efc4a314..860bcdbdc 100644 --- a/lib/preprocessor.js +++ b/lib/preprocessor.js @@ -38,12 +38,14 @@ var createNextProcessor = function (preprocessors, file, done) { } var createPreprocessor = function (config, basePath, injector) { - var alreadyDisplayedWarnings = {} + var alreadyDisplayedErrors = {} var instances = {} var patterns = Object.keys(config) + var emitter = injector.get('emitter') + var instantiatePreprocessor = function (name) { - if (alreadyDisplayedWarnings[name]) { + if (alreadyDisplayedErrors[name]) { return } @@ -53,13 +55,13 @@ var createPreprocessor = function (config, basePath, injector) { p = injector.get('preprocessor:' + name) } catch (e) { if (e.message.indexOf('No provider for "preprocessor:' + name + '"') !== -1) { - log.warn('Can not load "%s", it is not registered!\n ' + - 'Perhaps you are missing some plugin?', name) + log.error('Can not load "%s", it is not registered!\n ' + + 'Perhaps you are missing some plugin?', name) } else { - log.warn('Can not load "%s"!\n ' + e.stack, name) + log.error('Can not load "%s"!\n ' + e.stack, name) } - - alreadyDisplayedWarnings[name] = true + alreadyDisplayedErrors[name] = true + emitter.emit('load_error', 'preprocessor', name) } return p @@ -105,9 +107,10 @@ var createPreprocessor = function (config, basePath, injector) { } if (p == null) { - if (!alreadyDisplayedWarnings[name]) { - alreadyDisplayedWarnings[name] = true - log.warn('Failed to instantiate preprocessor %s', name) + if (!alreadyDisplayedErrors[name]) { + alreadyDisplayedErrors[name] = true + log.error('Failed to instantiate preprocessor %s', name) + emitter.emit('load_error', 'preprocessor', name) } return } diff --git a/lib/reporter.js b/lib/reporter.js index 22a21de88..cac9deea3 100644 --- a/lib/reporter.js +++ b/lib/reporter.js @@ -107,11 +107,12 @@ var createReporters = function (names, config, emitter, injector) { reporters.push(injector.createChild([locals], ['reporter:' + name]).get('reporter:' + name)) } catch (e) { if (e.message.indexOf('No provider for "reporter:' + name + '"') !== -1) { - log.warn('Can not load "%s", it is not registered!\n ' + + log.error('Can not load reporter "%s", it is not registered!\n ' + 'Perhaps you are missing some plugin?', name) } else { - log.warn('Can not load "%s"!\n ' + e.stack, name) + log.error('Can not load "%s"!\n ' + e.stack, name) } + emitter.emit('load_error', 'reporter', name) return } var color_name = name + '_color' diff --git a/lib/server.js b/lib/server.js index 739ac8617..189935778 100644 --- a/lib/server.js +++ b/lib/server.js @@ -51,6 +51,8 @@ var Server = function (cliOptions, done) { this.log = logger.create() + this.loadErrors = [] + var config = cfg.parseConfig(cliOptions.configFile, cliOptions) var modules = [{ @@ -58,6 +60,7 @@ var Server = function (cliOptions, done) { logger: ['value', logger], done: ['value', done || process.exit], emitter: ['value', this], + server: ['value', this], launcher: ['type', Launcher], config: ['value', config], preprocess: ['factory', preprocessor.createPreprocessor], @@ -82,8 +85,9 @@ var Server = function (cliOptions, done) { }] }] + this._setUpLoadErrorListener() // Load the plugins - modules = modules.concat(plugin.resolve(config.plugins)) + modules = modules.concat(plugin.resolve(config.plugins, this)) this._injector = new di.Injector(modules) } @@ -169,12 +173,16 @@ Server.prototype._start = function (config, launcher, preprocess, fileList, webS config.protocol, config.hostname, config.port, config.urlRoot) self.emit('listening', config.port) - if (config.browsers && config.browsers.length) { self._injector.invoke(launcher.launch, launcher).forEach(function (browserLauncher) { singleRunDoneBrowsers[browserLauncher.id] = false }) } + var noLoadErrors = self.loadErrors.length + if (noLoadErrors > 0) { + self.log.error('Found %d load error%s', noLoadErrors, noLoadErrors === 1 ? '' : 's') + process.kill(process.pid, 'SIGINT') + } }) } @@ -363,6 +371,14 @@ Server.prototype._start = function (config, launcher, preprocess, fileList, webS }) } +Server.prototype._setUpLoadErrorListener = function () { + var self = this + self.on('load_error', function (type, name) { + self.log.debug('Registered a load error of type %s with name %s', type, name) + self.loadErrors.push([type, name]) + }) +} + Server.prototype._detach = function (config, done) { var log = this.log var tmpFile = tmp.fileSync({keep: true}) diff --git a/test/e2e/load.feature b/test/e2e/load.feature new file mode 100644 index 000000000..865f211a7 --- /dev/null +++ b/test/e2e/load.feature @@ -0,0 +1,106 @@ +Feature: Basic Testrunner + In order to use Karma + As a person who wants to write great tests + I want Karma to terminate upon misconfiguration + + Scenario: Execute with missing browser + Given a configuration with: + """ + files = ['basic/plus.js', 'basic/test.js']; + browsers = ['NonExistingBrowser', 'PhantomJS']; + plugins = [ + 'karma-jasmine', + 'karma-phantomjs-launcher' + ]; + singleRun = false + """ + When I start Karma + Then it fails with like: + """ + Cannot load browser "NonExistingBrowser": it is not registered! Perhaps you are missing some plugin\? + """ + And it fails with like: + """ + Found 1 load error + """ + + Scenario: Execute with missing plugin + Given a configuration with: + """ + files = ['basic/plus.js', 'basic/test.js']; + browsers = ['PhantomJS']; + plugins = [ + 'karma-totally-non-existing-plugin', + 'karma-jasmine', + 'karma-phantomjs-launcher' + ]; + singleRun = false + """ + When I start Karma + Then it fails with like: + """ + Cannot find plugin "karma-totally-non-existing-plugin". + [\s]+Did you forget to install it\? + [\s]+npm install karma-totally-non-existing-plugin --save-dev + """ + And it fails with like: + """ + Found 1 load error + """ + + Scenario: Execute with missing reporter + Given a configuration with: + """ + files = ['basic/plus.js', 'basic/test.js']; + browsers = ['PhantomJS']; + reporters = ['unreal-reporter'] + plugins = [ + 'karma-jasmine', + 'karma-phantomjs-launcher' + ]; + singleRun = false + """ + When I start Karma + Then it fails with like: + """ + Can not load reporter "unreal-reporter", it is not registered! + [\s]+Perhaps you are missing some plugin\? + """ + And it fails with like: + """ + Found 1 load error + """ + + Scenario: Execute with missing reporter, plugin and browser + Given a configuration with: + """ + files = ['basic/plus.js', 'basic/test.js']; + browsers = ['NonExistingBrowser', 'PhantomJS']; + reporters = ['unreal-reporter'] + plugins = [ + 'karma-totally-non-existing-plugin', + 'karma-jasmine', + 'karma-phantomjs-launcher' + ]; + singleRun = false + """ + When I start Karma + Then it fails with like: + """ + Can not load reporter "unreal-reporter", it is not registered! + [\s]+Perhaps you are missing some plugin\? + """ + And it fails with like: + """ + Cannot find plugin "karma-totally-non-existing-plugin". + [\s]+Did you forget to install it\? + [\s]+npm install karma-totally-non-existing-plugin --save-dev + """ + And it fails with like: + """ + Cannot load browser "NonExistingBrowser": it is not registered! Perhaps you are missing some plugin\? + """ + And it fails with like: + """ + Found 3 load errors + """ diff --git a/test/unit/launcher.spec.js b/test/unit/launcher.spec.js index 109664d9c..dfbde5842 100644 --- a/test/unit/launcher.spec.js +++ b/test/unit/launcher.spec.js @@ -69,18 +69,22 @@ describe('launcher', () => { describe('Launcher', () => { var emitter - var l = emitter = null + var server + var l = emitter = server = null beforeEach(() => { emitter = new events.EventEmitter() + server = {'loadErrors': []} + var injector = new di.Injector([{ 'launcher:Fake': ['type', FakeBrowser], 'launcher:Script': ['type', ScriptBrowser], + 'server': ['value', server], 'emitter': ['value', emitter], 'config': ['value', {captureTimeout: 0}], 'timer': ['factory', createMockTimer] }]) - l = new launcher.Launcher(emitter, injector) + l = new launcher.Launcher(server, emitter, injector) }) describe('launch', () => { @@ -93,6 +97,15 @@ describe('launcher', () => { expect(browser.name).to.equal('Fake') }) + it('should not start when server has load errors', () => { + server.loadErrors = ['error'] + l.launch(['Fake'], 'http:', 'localhost', 1234, '/root/', 1) + var browser = FakeBrowser._instances.pop() + expect(browser.start).to.not.have.been.called + expect(browser.id).to.equal(lastGeneratedId) + expect(browser.name).to.equal('Fake') + }) + it('should allow launching a script', () => { l.launch(['/usr/local/bin/special-browser'], 'http:', 'localhost', 1234, '/', 1) diff --git a/test/unit/preprocessor.spec.js b/test/unit/preprocessor.spec.js index c995bdc4c..c0974e6a1 100644 --- a/test/unit/preprocessor.spec.js +++ b/test/unit/preprocessor.spec.js @@ -1,12 +1,13 @@ import mocks from 'mocks' import di from 'di' import path from 'path' +import events from '../../lib/events' describe('preprocessor', () => { var pp var m var mockFs - + var emitterSetting // mimic first few bytes of a pdf file var binarydata = new Buffer([0x25, 0x50, 0x44, 0x66, 0x46, 0x00]) @@ -28,7 +29,7 @@ describe('preprocessor', () => { 'graceful-fs': mockFs, minimatch: require('minimatch') } - + emitterSetting = {'emitter': ['value', new events.EventEmitter()]} m = mocks.loadFile(path.join(__dirname, '/../../lib/preprocessor.js'), mocks_) }) @@ -38,7 +39,7 @@ describe('preprocessor', () => { done(null, 'new-content') }) - var injector = new di.Injector([{'preprocessor:fake': ['factory', () => fakePreprocessor]}]) + var injector = new di.Injector([{'preprocessor:fake': ['factory', () => fakePreprocessor]}, emitterSetting]) pp = m.createPreprocessor({'**/*.js': ['fake']}, null, injector) var file = {originalPath: '/some/a.js', path: 'path'} @@ -57,7 +58,7 @@ describe('preprocessor', () => { done(null, 'new-content') }) - var injector = new di.Injector([{'preprocessor:fake': ['factory', () => fakePreprocessor]}]) + var injector = new di.Injector([{'preprocessor:fake': ['factory', () => fakePreprocessor]}, emitterSetting]) pp = m.createPreprocessor({'**/*.js': ['fake']}, null, injector) var file = {originalPath: '/some/.dir/a.js', path: 'path'} @@ -76,7 +77,7 @@ describe('preprocessor', () => { done(null, 'new-content') }) - var injector = new di.Injector([{'preprocessor:fake': ['factory', () => fakePreprocessor]}]) + var injector = new di.Injector([{'preprocessor:fake': ['factory', () => fakePreprocessor]}, emitterSetting]) var config = {'**/*.txt': ['fake']} pp = m.createPreprocessor(config, null, injector) @@ -97,7 +98,7 @@ describe('preprocessor', () => { done(null, '') }) - var injector = new di.Injector([{'preprocessor:fake': ['factory', () => fakePreprocessor]}]) + var injector = new di.Injector([{'preprocessor:fake': ['factory', () => fakePreprocessor]}, emitterSetting]) pp = m.createPreprocessor({'**/*.js': ['fake']}, null, injector) var file = {originalPath: '/some/a.txt', path: 'path'} @@ -122,7 +123,7 @@ describe('preprocessor', () => { var injector = new di.Injector([{ 'preprocessor:fake1': ['factory', () => fakePreprocessor1], 'preprocessor:fake2': ['factory', () => fakePreprocessor2] - }]) + }, emitterSetting]) pp = m.createPreprocessor({'**/*.js': ['fake1', 'fake2']}, null, injector) @@ -138,7 +139,7 @@ describe('preprocessor', () => { }) it('should compute SHA', (done) => { - pp = m.createPreprocessor({}, null, new di.Injector([])) + pp = m.createPreprocessor({}, null, new di.Injector([emitterSetting])) var file = {originalPath: '/some/a.js', path: 'path'} pp(file, () => { @@ -166,7 +167,7 @@ describe('preprocessor', () => { var injector = new di.Injector([{ 'preprocessor:fake': ['factory', () => fakePreprocessor] - }]) + }, emitterSetting]) pp = m.createPreprocessor({'**/a.js': ['fake']}, null, injector) @@ -192,7 +193,7 @@ describe('preprocessor', () => { var injector = new di.Injector([{ 'preprocessor:failing': ['factory', () => failingPreprocessor] - }]) + }, emitterSetting]) pp = m.createPreprocessor({'**/*.js': ['failing']}, null, injector) @@ -216,7 +217,7 @@ describe('preprocessor', () => { var injector = new di.Injector([{ 'preprocessor:failing': ['factory', () => failingPreprocessor], 'preprocessor:fake': ['factory', () => fakePreprocessor] - }]) + }, emitterSetting]) pp = m.createPreprocessor({'**/*.js': ['failing', 'fake']}, null, injector) @@ -235,7 +236,7 @@ describe('preprocessor', () => { var injector = new di.Injector([{ 'preprocessor:fake': ['factory', () => fakePreprocessor] - }]) + }, emitterSetting]) pp = m.createPreprocessor({'**/*': ['fake']}, null, injector) @@ -257,7 +258,7 @@ describe('preprocessor', () => { var injector = new di.Injector([{ 'preprocessor:fake': ['factory', () => fakePreprocessor] - }]) + }, emitterSetting]) pp = m.createPreprocessor({'**/*': ['fake']}, null, injector) @@ -296,7 +297,7 @@ describe('preprocessor', () => { 'preprocessor:fakeB': ['factory', () => fakePreprocessorB], 'preprocessor:fakeC': ['factory', () => fakePreprocessorC], 'preprocessor:fakeD': ['factory', () => fakePreprocessorD] - }]) + }, emitterSetting]) pp = m.createPreprocessor({ '/*/a.js': ['fakeA', 'fakeB'], From f7e81cc6260a49da4e7c0465ede246da34ede4aa Mon Sep 17 00:00:00 2001 From: Mourad Date: Mon, 29 Feb 2016 00:35:43 +0100 Subject: [PATCH 02/11] docs(config): docs(dev): Fix broken links in documentation. Fix broken links found in `dev\contributing.md` and `config\preprocessors.md`. --- docs/config/04-preprocessors.md | 2 +- docs/dev/01-contributing.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/config/04-preprocessors.md b/docs/config/04-preprocessors.md index 33b4edb00..ac9d30df7 100644 --- a/docs/config/04-preprocessors.md +++ b/docs/config/04-preprocessors.md @@ -18,7 +18,7 @@ Note: Most of the preprocessors need to be loaded as [plugins]. ## Available Preprocessors - [coffee] - [html2js] - - Note any .html files listed in the files section must be referenced at run time as `window.__html__['template.html']`. [Learn more](html2js). + - Note any .html files listed in the files section must be referenced at run time as `window.__html__['template.html']`. [Learn more](https://github.com/karma-runner/karma-html2js-preprocessor#how-does-it-work-). - If this preprocessor is disabled, included .html files will need `base/` added to beginning of their path reference. See [discussion in issue 788][issue788]. - [coverage] - [ng-html2js] diff --git a/docs/dev/01-contributing.md b/docs/dev/01-contributing.md index f9c1e29ba..79cc212f9 100644 --- a/docs/dev/01-contributing.md +++ b/docs/dev/01-contributing.md @@ -1,7 +1,7 @@ pageTitle: Contributing to Karma **Working on your first Pull Request?** You can learn how from this *free* series -[How to Contribute to an Open Source Project on GitHub](egghead_series) +[How to Contribute to an Open Source Project on GitHub] You wanna contribute to Karma? That is truly great! Here are some tips to get you started... @@ -54,4 +54,4 @@ You just do it. There is no test to pass ;-) [Stack Overflow]: http://stackoverflow.com/questions/tagged/karma-runner [`docs/`]: https://github.com/karma-runner/karma/tree/master/docs [Maintaining Karma]: ./maintaining.html -[egghead_series]: https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github +[How to Contribute to an Open Source Project on GitHub]: https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github From bb9ec1df77953d0c284de763fcac880a4bc93ac2 Mon Sep 17 00:00:00 2001 From: Mourad Date: Wed, 2 Mar 2016 20:07:37 +0100 Subject: [PATCH 03/11] docs: Fix grammar in the documentation files. Fix gramma in multiple documentation files, as they contained some grammar mistakes. It looks more professional with correct grammar. --- docs/about/03-migration.md | 4 +--- docs/config/01-configuration-file.md | 35 +++++++++++++++++++--------- docs/config/02-files.md | 4 ++-- docs/config/03-browsers.md | 10 ++++---- docs/config/04-preprocessors.md | 12 ++++------ docs/dev/01-contributing.md | 10 ++++---- docs/dev/02-making-changes.md | 2 +- docs/dev/03-maintaining.md | 4 ++-- docs/dev/04-public-api.md | 8 +++---- docs/dev/05-plugins.md | 6 ++--- docs/dev/06-git-commit-msg.md | 8 +++---- docs/intro/02-configuration.md | 14 +++++------ docs/intro/03-how-it-works.md | 2 +- docs/intro/04-faq.md | 10 ++++---- docs/intro/05-troubleshooting.md | 6 ++--- docs/plus/01-requirejs.md | 10 ++++---- docs/plus/02-travis.md | 12 ++++------ docs/plus/04-semaphore.md | 2 +- docs/plus/05-cloud9.md | 2 +- docs/plus/09-codio.md | 8 +++---- docs/plus/10-teamcity.md | 10 ++++---- 21 files changed, 92 insertions(+), 87 deletions(-) diff --git a/docs/about/03-migration.md b/docs/about/03-migration.md index 272971bab..21836d540 100644 --- a/docs/about/03-migration.md +++ b/docs/about/03-migration.md @@ -51,9 +51,7 @@ But hey, give it a shot first, it's really awesome to run your tests on every sa ## NPM complaining -In some cases NPM can run into dependency tree issues during the migration process. If you are faced -with an "unsatisfied peer dependency" error, removing all of the packages (`rm -rf ./node_modules`) and installing -them again should clear up the issue. +In some cases, NPM can run into dependency tree issues during the migration process. If you are faced with an "unsatisfied peer dependency" error, removing all of the packages (`rm -rf ./node_modules`) and installing them again should clear up the issue. If you have any other issues, please ask on the [mailing list]. diff --git a/docs/config/01-configuration-file.md b/docs/config/01-configuration-file.md index 2263c8f0a..fcb81e930 100644 --- a/docs/config/01-configuration-file.md +++ b/docs/config/01-configuration-file.md @@ -87,7 +87,7 @@ have occurred before starting the test process again. **Description:** The root path location that will be used to resolve all relative paths defined in `files` and `exclude`. If the `basePath` configuration is a -relative path then it will be resolved to the `__dirname` of the configuration file. +relative path, then it will be resolved to the `__dirname` of the configuration file. ## browserDisconnectTimeout @@ -97,8 +97,8 @@ relative path then it will be resolved to the `__dirname` of the configuration f **Description:** How long does Karma wait for a browser to reconnect (in ms). -With a flaky connection it is pretty common that the browser disconnects, but the actual test execution is still running -without any problems. Karma does not treat a disconnection as immediate failure and will wait `browserDisconnectTimeout` (ms). +With a flaky connection, it is pretty common that the browser disconnects, but the actual test execution is still running +without any problems. Karma does not treat a disconnection as an immediate failure and will wait for `browserDisconnectTimeout` (ms). If the browser reconnects during that time, everything is fine. @@ -110,7 +110,7 @@ If the browser reconnects during that time, everything is fine. **Description:** The number of disconnections tolerated. The `disconnectTolerance` value represents the maximum number of tries a browser will attempt in the case of a disconnection. -Usually any disconnection is considered a failure, but this option allows you to define a tolerance level when there is +Usually, any disconnection is considered a failure, but this option allows you to define a tolerance level when there is a flaky network link between the Karma server and the browsers. @@ -121,8 +121,7 @@ a flaky network link between the Karma server and the browsers. **Description:** How long will Karma wait for a message from a browser before disconnecting from it (in ms). -If, during test execution, Karma does not receive any message from a browser within `browserNoActivityTimeout` -(ms), it will disconnect from the browser. +If, during test execution, Karma does not receive any message from a browser within `browserNoActivityTimeout`(ms), it will disconnect from the browser. ## browsers @@ -172,8 +171,7 @@ it again and, after three attempts to capture it, Karma will give up. are passed through to the test adapter as `karma.config.args` (an array of strings). The `client.args` option allows you to set this value for actions other than `run`. -How this value is used is up to your test adapter - you should check your adapter's -documentation to see how (and if) it uses this value. +How this value is used is up to your test adapter - you should check your adapter's documentation to see how (and if) it uses this value. ## client.useIframe @@ -203,7 +201,7 @@ iFrame and may need a new window to run. **Description:** Clear the context window If true, Karma clears the context window upon the completion of running the tests. If false, Karma does not clear the context window -upon the completion of running the tests. Setting this to false is useful when embedding a Jasmine Spec Runner Template. +upon the completion of running the tests. Setting this to false is useful when embedding a Jasmine Spec Runner Template. ## colors **Type:** Boolean @@ -220,9 +218,9 @@ upon the completion of running the tests. Setting this to false is useful when **Default:** `Infinity` -**Description:** How many browser Karma launches in parallel. +**Description:** How many browsers Karma launches in parallel. -Especially on services like SauceLabs and Browserstack it makes sense to only launch a limited amount of browsers at once, and only start more when those have finished. Using this configuration you can specify how many browsers should be running at once at any given point in time. +Especially on services like SauceLabs and Browserstack, it makes sense only to launch a limited amount of browsers at once, and only start more when those have finished. Using this configuration, you can specify how many browsers should be running at once at any given point in time. ## customContextFile @@ -241,6 +239,21 @@ Especially on services like SauceLabs and Browserstack it makes sense to only la **Description:** If `null` (default), uses karma's own `debug.html` file. +## customContextFile +**Type:** string + +**Default:** `null` + +**Description:** If `null` (default), uses karma's own `context.html` file. + + +## customDebugFile +**Type:** string + +**Default:** `null` + +**Description:** If `null` (default), uses karma's own `debug.html` file. + ## customHeaders **Type:** Array diff --git a/docs/config/02-files.md b/docs/config/02-files.md index 7f4ee2fa0..aa9f93f1f 100644 --- a/docs/config/02-files.md +++ b/docs/config/02-files.md @@ -89,13 +89,13 @@ files: [ ], ``` -The pattern is a glob which matches the specified image assets. Watched and included are not necessary as images are not tests. However they will need to be served to the browser. +The pattern is a glob which matches the specified image assets. Watched and included are not necessary as images are not tests. However, they will need to be served to the browser. In this case an image would be accessed at `http://localhost:[PORT]/base/test/images/[MY IMAGE].jpg` Notice the **base** in the URL, it is a reference to your **basePath**. You do not need to replace or provide your own **base**. -In addition you can use a proxy +In addition, you can use a proxy ```javascript proxies: { diff --git a/docs/config/03-browsers.md b/docs/config/03-browsers.md index c5e53efa4..793f32798 100644 --- a/docs/config/03-browsers.md +++ b/docs/config/03-browsers.md @@ -1,4 +1,4 @@ -Capturing browsers on your own can be a tedious and time consuming task, +Capturing browsers on your own can be a tedious and time-consuming task, so Karma can automate this for you. Simply add the browsers you would like to capture into the configuration file: @@ -38,7 +38,7 @@ module.exports = function(config) { }; ``` -Also keep in mind that the `browsers` configuration setting is empty by default. +Also, keep in mind that the `browsers` configuration setting is empty by default. Of course, you can write [custom plugins] too! @@ -53,7 +53,7 @@ as the machine running Karma (or using a local tunnel). ## Configured launchers -Some of the launchers can be also configured: +Some of the launchers can also be configured: ```javascript sauceLabs: { @@ -126,9 +126,7 @@ browsers: ['/usr/local/bin/custom-browser.sh'], // from cli karma start --browsers /usr/local/bin/custom-browser.sh ``` -The browser scripts need to take one argument, which is the URL with the ID -parameter to be used to connect to the server. The supplied ID is used -by the server to keep track of which specific browser is captured. +The browser scripts need to take one argument, which is the URL with the ID-parameter to be used to connect to the server. The supplied ID is used by the server to keep track of which specific browser is captured. diff --git a/docs/config/04-preprocessors.md b/docs/config/04-preprocessors.md index 33b4edb00..73845efc5 100644 --- a/docs/config/04-preprocessors.md +++ b/docs/config/04-preprocessors.md @@ -47,7 +47,7 @@ Of course, you can write [custom plugins] too! ## Configured Preprocessors -Some of the preprocessors can be also configured: +Some of the preprocessors can also be configured: ```javascript coffeePreprocessor: { @@ -69,7 +69,7 @@ customPreprocessors: { ``` -## Minimatching +## Mini matching The keys of the preprocessors config object are used to filter the files specified in the `files` configuration. @@ -98,7 +98,7 @@ return `false` and the preprocessor would not be executed on the CoffeeScript fi If a file matches only one key in the preprocessors config object, then karma will execute the preprocessors over that file in the order they are listed in -the corresponding array. So for instance if the config object is: +the corresponding array. So for instance, if the config object is: ```js preprocessors: { @@ -118,9 +118,7 @@ preprocessors: { } ``` -then for `a.js`, karma will run `'a'` then `'b'` then `'c'`. If two lists -contradict eachother, like: - +then for `a.js`, karma will run `'a'` then `'b'` then `'c'`. If two lists contradict each other, like: ```js preprocessors: { '*.js': ['a', 'b'], @@ -139,4 +137,4 @@ preprocessors: { ``` Then `'a'` will definitely be run first, `'d'` will definitely be run last, but -it's arbitrarily if karma will run `'b'` before `'c'` or vice versa. +it's arbitrary if karma will run `'b'` before `'c'` or vice versa. diff --git a/docs/dev/01-contributing.md b/docs/dev/01-contributing.md index f9c1e29ba..a615004da 100644 --- a/docs/dev/01-contributing.md +++ b/docs/dev/01-contributing.md @@ -3,7 +3,7 @@ pageTitle: Contributing to Karma **Working on your first Pull Request?** You can learn how from this *free* series [How to Contribute to an Open Source Project on GitHub](egghead_series) -You wanna contribute to Karma? That is truly great! +You want to contribute to Karma? That is truly great! Here are some tips to get you started... ### Help others @@ -16,17 +16,17 @@ Soon, you will realize you know Karma pretty well... ### Improve the documentation -You don’t feel like hacking on the code, but still wanna help? +You don’t feel like hacking on the code, but still want to help? Improving the documentation is very valuable as it will help many others. All the source code is in [`docs/`]. ### Fix something that bothers you -You found a bug that really bothers you? It’s more likely it bothers other users too and maybe +Did you find a bug that really bothers you? It’s more likely it bothers other users too, and maybe it’s not that hard to fix it! Try to find an existing issue. If it does not exist yet, create one. Look into the code and let others know what solution you are thinking about. -Then, send a pull request and let other contributors to review. +Then, send a pull request and let other contributors review. [Here](./making-changes.html) is some more info on how to set up your workspace and send a pull request. @@ -46,7 +46,7 @@ Check out the list of outstanding pull requests if there is something you might Maybe somebody is trying to fix that stupid bug that bothers you. Review the PR. Do you have any better ideas how to fix this problem? Let us know... -### I wanna help more +### I want to help more Check out [Maintaining Karma]. Becoming a Karma maintainer is simple. You just do it. There is no test to pass ;-) diff --git a/docs/dev/02-making-changes.md b/docs/dev/02-making-changes.md index 31c566e91..5f727bbe2 100644 --- a/docs/dev/02-making-changes.md +++ b/docs/dev/02-making-changes.md @@ -88,7 +88,7 @@ your changes in. ## Contributor License Agreement Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code changes to be accepted, the CLA must be signed. It's a quick process, we promise! -- For individuals we have a [simple click-through form]. +- For individuals, we have a [simple click-through form]. - For corporations we'll need you to print, sign and one of scan+email, fax or mail [the form]. ## Additional Resources diff --git a/docs/dev/03-maintaining.md b/docs/dev/03-maintaining.md index f17bc3f18..9d93f1238 100644 --- a/docs/dev/03-maintaining.md +++ b/docs/dev/03-maintaining.md @@ -38,11 +38,11 @@ Every project has one or more owners (or “maintainers”), listed in `owners` Being a maintainer of one plugin doesn’t mean you can’t contribute to some other plugins. In fact, you can be a maintainer of multiple projects. The main point is to have people who are -familiar with the codebase and therefore can better decide what is a good change or not. +familiar with the codebase and therefore can better decide what a good change is or not. ## Becoming a maintainer -If you are interest in becoming a Karma maintainer, start by triaging issues, reviewing pull +If you are interested in becoming a Karma maintainer, start by triaging issues, reviewing pull requests and stop by at [gitter/karma-runner]. Once we see you are helping, we will give you push permissions. Being a maintainer is not an obligation. You can help when you have time and be less active when you don’t. If you get a new job and get busy, that’s alright. diff --git a/docs/dev/04-public-api.md b/docs/dev/04-public-api.md index 2c341f646..6c4e580fe 100644 --- a/docs/dev/04-public-api.md +++ b/docs/dev/04-public-api.md @@ -60,7 +60,7 @@ A new browser was opened, but is not ready yet. * `browser`: The browser instance * `error`: The error that occurred -There was an error on this browser instance. +There was an error in this browser instance. ### `browser_start` **Arguments:** @@ -108,7 +108,7 @@ A test run was completed. ### **runner.run(options, [callback=process.exit])** -Equivalent of `karma run`. +The equivalent of `karma run`. ```javascript var runner = require('karma').runner @@ -122,7 +122,7 @@ runner.run({port: 9876}, function(exitCode) { ### **stopper.stop(options, [callback=process.exit])** -This function will signal a running server to stop. Equivalent of `karma stop`. +This function will signal a running server to stop. The equivalent of `karma stop`. ```javascript var stopper = require('karma').stopper @@ -136,4 +136,4 @@ runner.stop({port: 9876}, function(exitCode) { ## Callback function notes -- If there is an error, the error code will be provided as the second parameter to the error callback. +- If there is an error, the error code will be provided as the second parameter to the error callback. \ No newline at end of file diff --git a/docs/dev/05-plugins.md b/docs/dev/05-plugins.md index fc6a9e324..477fe607d 100644 --- a/docs/dev/05-plugins.md +++ b/docs/dev/05-plugins.md @@ -23,7 +23,7 @@ Karma can be extended through plugins. A plugin is essentially an NPM module. Ty - user NPM keywords `karma-plugin`, `karma-preprocessor` ## Crazier stuff -Karma is assembled by Dependency Injection and a plugin is just an additional DI module (see [node-di] for more), that can be loaded by Karma. Therefore it can ask for pretty much any Karma component and interact with it. There are couple of plugins that do more interesting stuff like this, check out [karma-closure], [karma-intellij], [karma-dart]. +Karma is assembled by Dependency Injection and a plugin is just an additional DI module (see [node-di] for more), that can be loaded by Karma. Therefore, it can ask for pretty much any Karma component and interact with it. There are a couple of plugins that do more interesting stuff like this, check out [karma-closure], [karma-intellij], [karma-dart]. [karma-jasmine]: https://github.com/karma-runner/karma-jasmine @@ -43,7 +43,7 @@ Karma is assembled by Dependency Injection and a plugin is just an additional DI ## Karma Framework API -Karma Framework connect existing testing libraries to Karma's API, so that their +Karma Framework connects existing testing libraries to Karma's API, so that their results can be displayed in a browser and sent back to the server. Karma frameworks _must_ implement a `window.__karma__.start` method that Karma will @@ -53,7 +53,7 @@ to send results back to karma: * `.result` a single test has finished * `.complete` the client completed execution of all the tests * `.error` an error happened in the client -* `.info` other data (eg. number of tests or debugging messages) +* `.info` other data (e.g. number of tests or debugging messages) Most commonly you'll use the `result` method to send individual test success or failure statuses. The method takes an object of the form: diff --git a/docs/dev/06-git-commit-msg.md b/docs/dev/06-git-commit-msg.md index 3565b4ed4..ce8bd0dd6 100644 --- a/docs/dev/06-git-commit-msg.md +++ b/docs/dev/06-git-commit-msg.md @@ -2,7 +2,7 @@ showInMenu: false ## The reasons for these conventions: - automatic generating of the changelog -- simple navigation through git history (eg. ignoring style changes) +- simple navigation through git history (e.g. ignoring style changes) ## Format of the commit message: ```bash @@ -15,7 +15,7 @@ showInMenu: false ## Message subject (first line) -First line cannot be longer than 70 characters, second line is always blank and +The first line cannot be longer than 70 characters, the second line is always blank and other lines should be wrapped at 80 characters. The type and scope should always be lowercase as shown below. @@ -39,7 +39,7 @@ always be lowercase as shown below. * proxy * etc. -The `` can be empty (eg. if the change is a global or difficult +The `` can be empty (e.g. if the change is a global or difficult to assign to a single component), in which case the parentheses are omitted. In smaller projects such as Karma plugins, the `` is empty. @@ -61,7 +61,7 @@ Closed issues should be listed on a separate line in the footer prefixed with "C ```bash Closes #234 ``` -or in case of multiple issues: +or in the case of multiple issues: ```bash Closes #123, #245, #992 ``` diff --git a/docs/intro/02-configuration.md b/docs/intro/02-configuration.md index 601168c11..a3bbfb19b 100644 --- a/docs/intro/02-configuration.md +++ b/docs/intro/02-configuration.md @@ -9,34 +9,34 @@ The configuration file can be generated using `karma init`: ```bash $ karma init my.conf.js -Which testing framework do you want to use ? +Which testing framework do you want to use? Press tab to list possible options. Enter to move to the next question. > jasmine -Do you want to use Require.js ? +Do you want to use Require.js? This will add Require.js plugin. Press tab to list possible options. Enter to move to the next question. > no -Do you want to capture a browser automatically ? +Do you want to capture a browser automatically? Press tab to list possible options. Enter empty string to move to the next question. > Chrome > Firefox > -What is the location of your source and test files ? +What is the location of your source and test files? You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js". Press Enter to move to the next question. > *.js > test/**/*.js > -Should any of the files included by the previous patterns be excluded ? +Should any of the files included by the previous patterns be excluded? You can use glob patterns, eg. "**/*.swp". Press Enter to move to the next question. > -Do you want Karma to watch all the files and run the tests on change ? +Do you want Karma to watch all the files and run the tests on change? Press tab to list possible options. > yes @@ -46,7 +46,7 @@ Config file generated at "/Users/vojta/Code/karma/my.conf.js". The configuration file can be written in CoffeeScript as well. In fact, if you execute `karma init` with a `*.coffee` extension such as `karma init karma.conf.coffee`, it will generate a CoffeeScript file. -Of course, you can write the config file by hand or copy paste it from another project ;-) +Of course, you can write the config file by hand or copy-paste it from another project ;-) ## Starting Karma When starting Karma, the configuration file path can be passed in as the first argument. diff --git a/docs/intro/03-how-it-works.md b/docs/intro/03-how-it-works.md index 52a1be950..61a1ce111 100644 --- a/docs/intro/03-how-it-works.md +++ b/docs/intro/03-how-it-works.md @@ -1,5 +1,5 @@ Karma is essentially a tool which spawns a web server that executes source code against test code for each of the browsers connected. -The results for each test against each browser are examined and displayed via the command line to the developer +The results of each test against each browser are examined and displayed via the command line to the developer such that they can see which browsers and tests passed or failed. A browser can be captured either diff --git a/docs/intro/04-faq.md b/docs/intro/04-faq.md index 1716fa912..8b365455f 100644 --- a/docs/intro/04-faq.md +++ b/docs/intro/04-faq.md @@ -5,26 +5,26 @@ The list below is a collection of common questions regarding Karma and its use. If you have any other questions in mind, please visit the [mailing list] to let the community know. -### Can I use Karma with testing framework X ? +### Can I use Karma with testing framework X? Yes. There are plugins for most of the common testing frameworks (such as Jasmine, Mocha, QUnit). If there is no plugin for the testing framework you like, go ahead and write one. It is simple - you can start by looking into the source code of the existing ones. -### Can I use Karma to do end to end testing ? +### Can I use Karma to do end to end testing? Karma has primarily been designed for low level (unit) testing. If it's an AngularJS app, you can -use Karma with [karma-ng-scenario] plugin, however we recommend [Protractor] for high level testing. +use Karma with the [karma-ng-scenario] plugin. However, we recommend [Protractor] for high-level testing. ### Can I use Karma on Continuous Integration server ? Of course! Check out the docs for [Jenkins], [Semaphore], [TeamCity] or [Travis]. -### Which version of Karma should I use ? +### Which version of Karma should I use? The latest stable version from NPM (`npm install karma`). See [versioning] for more detailed information about Karma's release channels. -### Which version of Node.js does Karma run with ? +### Which version of Node.js does Karma run with? Karma works on all LTS versions node in active maintenance state (see [LTS docs](https://github.com/nodejs/LTS/blob/master/README.md) for more info) as well as the latest stable version. That is **0.12.x**, **4.x** and **5.x** at this point. Additionally, Node **0.10** is currently supported. diff --git a/docs/intro/05-troubleshooting.md b/docs/intro/05-troubleshooting.md index a1d1ea4fe..7d53fbff7 100644 --- a/docs/intro/05-troubleshooting.md +++ b/docs/intro/05-troubleshooting.md @@ -19,11 +19,11 @@ If you have issues to update NPM, you can just go to the [NodeJS](http://nodejs. ### The browser just does not start. What's going on? It's more likely Karma can't find the location of the browser binary (the execution file). You can fix this by setting -the appropriate environment variable with the correct path (Google Chrome for instance uses the `CHROME_BIN` environment variable). +the appropriate environment variable with the correct path (Google Chrome, for instance, uses the `CHROME_BIN` environment variable). Check out [browsers] for more information. -### I'm getting a weird error from the browser, how can I debug it ? +### I'm getting a weird error from the browser, how can I debug it? Go to the captured browser and click the "DEBUG" button (or open `http://localhost:9876/debug.html`) and use the web inspector to see what's going on. (You may need to refresh the debug.html page for it to kick in once the web inspector is open.) @@ -35,7 +35,7 @@ See preprocessors for more information. You can also turn on debug logging (use and Karma will display which files are preprocessed. -### I'm getting a `npm ERR! peerinvalid Peer` error. How can I fix that ? +### I'm getting a `npm ERR! peerinvalid Peer` error. How can I fix that? Try to remove `karma` and `karma-*` modules from your `node_modules` first (for instance `rm -rf /usr/local/lib/node_modules/karma-*`), then install Karma again. diff --git a/docs/plus/01-requirejs.md b/docs/plus/01-requirejs.md index 9141872e0..f4841399d 100644 --- a/docs/plus/01-requirejs.md +++ b/docs/plus/01-requirejs.md @@ -39,14 +39,14 @@ $ karma init This will give you a series of prompts for things such as paths to the source and test files as well as which browsers to capture. -In this example we'll use Jasmine, but other test frameworks works just +In this example we'll use Jasmine, but other test frameworks work just as well. Choose "yes" for Require.js. For the question *"Which files do you want to include with <script> tag?"*, we need to choose all files which are *not* loaded by Require.js. -Usually you'll only need to include your `test-main.js` file, which has +Usually, you'll only need to include your `test-main.js` file, which has the same role for your tests as `main.js` has for your app when using Require.js. @@ -88,7 +88,7 @@ The files property contains every file you want to be available to the Karma runner. By default a script tag will be created for the files, unless you use the `included: false` option. -If you want a script tag to be added before requirejs (to load a amd +If you want a script tag to be added before requirejs (to load an amd compatible script before requirejs) then you must add the requirejs and adapter script to the files list and remove requirejs from the frameworks list. This allows you to control the order. For instance @@ -125,7 +125,7 @@ requests to files will be served up under The Require.js config for `baseUrl` gives a starting context for modules that load with relative paths. When setting this value for the Karma -server it will need to start with `/base`. We want the `baseUrl` for our +server, it will need to start with `/base`. We want the `baseUrl` for our tests to be the same folder as the base url we have in `src/main.js`, so that relative requires in the source won’t need to change. So, as we want our base url to be at `src/`, we need to write `/base/src`. @@ -160,7 +160,7 @@ require.config({ // Karma serves files under /base, which is the basePath from your config file baseUrl: '/base/src', - // example of using a couple path translations (paths), to allow us to refer to different library dependencies, without using relative paths + // example of using a couple of path translations (paths), to allow us to refer to different library dependencies, without using relative paths paths: { 'jquery': '../lib/jquery', 'underscore': '../lib/underscore', diff --git a/docs/plus/02-travis.md b/docs/plus/02-travis.md index 5f993868d..e05cb465d 100644 --- a/docs/plus/02-travis.md +++ b/docs/plus/02-travis.md @@ -3,7 +3,7 @@ menuTitle: Travis CI [Travis CI] is a popular continuous integration service that integrates with your [Github] repository to automatically run your -tests when code is pushed. Integration is done by adding a simple +tests when the code is pushed. Integration is done by adding a simple [YAML] file to your project root; Travis and Github take care of the rest. Whenever tested, the Travis results will appear in your Github pull requests and your history will be available within their control panel. This article assumes you @@ -20,8 +20,7 @@ node_js: ``` ## Set up a Test Command -If you do not already have a `package.json` in your project root -create one now. Travis runs `npm test` to trigger your tests so this +If you do not already have a `package.json` in your project root, create one now. Travis runs `npm test` to trigger your tests, so this is where you tell Travis how to run your tests. ```json @@ -36,7 +35,7 @@ is where you tell Travis how to run your tests. // ...snip... ``` -Travis will run `npm install` before every suite so this is your +Travis will run `npm install` before every suite, so this is your chance to specify any modules your app needs that Travis does not know about like Karma. @@ -62,9 +61,8 @@ karma start --browsers Firefox --single-run ## Notes * Travis' Node environment has very little available. If the startup - process in Travis fails check for missing module information and be - sure to add them to your `package.json` dependencies. -* Travis does not run in your local network so any code that attempts + process in Travis fails to check for missing module information and be sure to add them to your `package.json` dependencies. +* Travis does not run on your local network so any code that attempts to connect to resources should be stubbed out using [Nock]. * There are more options available to your `.travis.yml`, such as running scripts before the install or test run. There are hints in diff --git a/docs/plus/04-semaphore.md b/docs/plus/04-semaphore.md index cb815dcbf..5760c3c29 100644 --- a/docs/plus/04-semaphore.md +++ b/docs/plus/04-semaphore.md @@ -49,7 +49,7 @@ npm test ``` That's it - proceed to your first build. In case you're using Firefox as -your test browser, Semaphore will automatically run it in a virtual screen +your test browser, Semaphore will automatically run it on a virtual screen during your builds. Also, if necessary, build commands can be further [customized] at any time. diff --git a/docs/plus/05-cloud9.md b/docs/plus/05-cloud9.md index 331554d1b..8a4a4194d 100644 --- a/docs/plus/05-cloud9.md +++ b/docs/plus/05-cloud9.md @@ -1,6 +1,6 @@ [Cloud9 IDE] is an open source web-based cloud integrated development environment that supports several programming languages, with a focus on the web stack (specifically JavaScript and NodeJS). -It is written almost entirely in JavaScript, and uses NodeJS on the back-end. +It is written almost entirely in JavaScript and uses NodeJS on the back-end. ## Configuration diff --git a/docs/plus/09-codio.md b/docs/plus/09-codio.md index 0844005eb..6fc08839d 100644 --- a/docs/plus/09-codio.md +++ b/docs/plus/09-codio.md @@ -1,4 +1,4 @@ -[Codio] is a web-based cloud integrated development environment that supports almost any programming language. Every project gets its own Box: an instantly available server-side development environment with full terminal access. Unlimited panels and tabs, and a plethora of productivity features. +[Codio] is a web-based cloud integrated development environment that supports almost any programming language. Every project gets its individual Box: an instantly available server-side development environment with full terminal access. Unlimited panels and tabs, and a plethora of productivity features. ##Customize your Codio Project @@ -53,10 +53,10 @@ You can use your local browser. $ karma start --no-browsers or - - Select `Karma Start` from the Run menu (the 2nd from right button). + - Select `Karma Start` from the Run menu (the 2nd from the right button). -- Select `Karma Preview` from the Preview menu (the right hand button). +- Select `Karma Preview` from the Preview menu (the right-hand button). - Switch back into your Codio project and either: @@ -64,7 +64,7 @@ or $ karma run or - - Select `Karma Run` from the Run menu (the 2nd from right button). + - Select `Karma Run` from the Run menu (the 2nd from the right button). and your test will execute diff --git a/docs/plus/10-teamcity.md b/docs/plus/10-teamcity.md index 67d9c443b..d45970a68 100644 --- a/docs/plus/10-teamcity.md +++ b/docs/plus/10-teamcity.md @@ -2,7 +2,7 @@ pageTitle: TeamCity menuTitle: TeamCity Running Karma in your [TeamCity] build is as simple as adding command line build -step to perform the task. Basically that is it. +step to perform the task. That is basically it. ## Install Prerequisites The only prerequisite is `Node` (with `npm`) installed on the agent(s) you are going to use to @@ -17,12 +17,12 @@ Add `karma-teamcity-reporter` as a dependency to your project: It is also a good idea to check that you have all karma npm dependencies listed in your `package.json` file (e.g. `karma-jasmine`, `karma-phantomjs-launcher` and so on) to have them -being installed during build. +being installed during the build. ## Create a new TeamCity build step -Add new build step to build configuration: use Command Line runner and fill in `Custom -script` textarea. If you had decided not to install *all* your NPM dependencies globally -add `npm install` in the beginning of the script. Then add command to run Karma, e.g.: +Add new build step to the build configuration: use Command Line runner and fill in `Custom +script` text area. If you had decided not to install *all* your NPM dependencies globally +add `npm install` at the beginning of the script. Then add command to run Karma, e.g.: karma start --reporters teamcity --single-run --browsers PhantomJS --colors false From ad87290d013836bd13b8b65d7b544a2381deaadf Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Thu, 3 Mar 2016 19:19:22 +0100 Subject: [PATCH 04/11] chore(package): update karma-script-launcher to version 0.2.0 http://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29ec294ab..ae79e3482 100644 --- a/package.json +++ b/package.json @@ -335,7 +335,7 @@ "karma-qunit": "*", "karma-requirejs": "*", "karma-sauce-launcher": "*", - "karma-script-launcher": "^0.1.0", + "karma-script-launcher": "^0.2.0", "load-grunt-tasks": "^3.1.0", "mkdirp": "^0.5.0", "mocha": "^2.4.1", From 08aad4705506d02c0cad48d299ae2223f4495a49 Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Sat, 5 Mar 2016 01:45:20 +0100 Subject: [PATCH 05/11] chore(package): update eslint to version 2.3.0 http://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ae79e3482..e57d043be 100644 --- a/package.json +++ b/package.json @@ -295,7 +295,7 @@ "chai-subset": "^1.0.1", "coffee-script": "^1.9.2", "cucumber": "^0.9.1", - "eslint": "^2.2.0", + "eslint": "^2.3.0", "eslint-config-standard": "^5.1.0", "eslint-plugin-promise": "^1.0.8", "eslint-plugin-react": "^4.0.0", From dff6e0ef5e2fabd55d5dfe9c2234bc92a6fbdb68 Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Sat, 5 Mar 2016 09:33:49 +0100 Subject: [PATCH 06/11] chore(package): update glob to version 7.0.3 http://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ae79e3482..0f4659b64 100644 --- a/package.json +++ b/package.json @@ -272,7 +272,7 @@ "di": "^0.0.1", "dom-serialize": "^2.2.0", "expand-braces": "^0.1.1", - "glob": "^7.0.0", + "glob": "^7.0.3", "graceful-fs": "^4.1.2", "http-proxy": "^1.13.0", "isbinaryfile": "^3.0.0", From f15cbaba7de786848aecae18c20a8d99d00b2af4 Mon Sep 17 00:00:00 2001 From: Derek Schaller Date: Sat, 5 Mar 2016 02:34:41 -0800 Subject: [PATCH 07/11] docs(config): update links of browser launchers --- docs/config/03-browsers.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/config/03-browsers.md b/docs/config/03-browsers.md index 793f32798..98f4b0c47 100644 --- a/docs/config/03-browsers.md +++ b/docs/config/03-browsers.md @@ -11,14 +11,14 @@ Then, Karma will take care of auto-capturing these browsers, as well as killing Note: Most of the browser launchers need to be loaded as [plugins]. ## Available browser launchers -- [Chrome and Chrome Canary] (install karma-chrome-launcher) -- [Firefox] (install karma-firefox-launcher first) -- [Safari] (install karma-safari-launcher first) -- [PhantomJS] (install karma-phantomjs-launcher) -- [Opera] (install karma-opera-launcher first) -- [IE] (install karma-ie-launcher first) -- [SauceLabs] (install karma-sauce-launcher) -- [BrowserStack] (install karma-browserstack-launcher) +- [Chrome and Chrome Canary](https://www.npmjs.com/package/karma-chrome-launcher) +- [Firefox](https://www.npmjs.com/package/karma-firefox-launcher) +- [Safari](https://www.npmjs.com/package/karma-safari-launcher) +- [PhantomJS](https://www.npmjs.com/package/karma-phantomjs-launcher) +- [Opera](https://www.npmjs.com/package/karma-opera-launcher) +- [IE](https://www.npmjs.com/package/karma-ie-launcher) +- [SauceLabs](https://www.npmjs.com/package/karma-saucelabs-launcher) +- [BrowserStack](https://www.npmjs.com/package/karma-browserstack-launcher) - [many more](https://www.npmjs.org/browse/keyword/karma-launcher) Here's an example of how to add Firefox to your testing suite: From 95e428276d2f0bbcda0fbc1fcc47fb58c0b971e8 Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Mon, 7 Mar 2016 11:54:22 +0100 Subject: [PATCH 08/11] chore(package): update karma-mocha-reporter to version 2.0.0 http://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 78f814844..c4593874b 100644 --- a/package.json +++ b/package.json @@ -329,7 +329,7 @@ "karma-junit-reporter": "*", "karma-live-preprocessor": "*", "karma-mocha": "0.2.1", - "karma-mocha-reporter": "^1.2.0", + "karma-mocha-reporter": "^2.0.0", "karma-ng-scenario": "*", "karma-phantomjs-launcher": "*", "karma-qunit": "*", From 8ef475f7d1a06562e659347dcc53c2e474cbddc7 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Mon, 7 Mar 2016 13:26:28 +0100 Subject: [PATCH 09/11] fix(web-server): Update config on every request This updates the `client`, `customContextFile` and `customDebugFile` config properties on every request in the karma middleware. Closes #1972 --- lib/middleware/karma.js | 26 ++++++--- lib/web-server.js | 1 + test/unit/middleware/karma.spec.js | 92 ++++++++++++++++++++++++++++-- 3 files changed, 107 insertions(+), 12 deletions(-) diff --git a/lib/middleware/karma.js b/lib/middleware/karma.js index 2e603b382..0c965a521 100644 --- a/lib/middleware/karma.js +++ b/lib/middleware/karma.js @@ -15,6 +15,8 @@ var path = require('path') var util = require('util') var url = require('url') +var log = require('../logger').create('middleware:karma') + var urlparse = function (urlStr) { var urlObj = url.parse(urlStr, true) urlObj.query = urlObj.query || {} @@ -59,10 +61,20 @@ var getXUACompatibleUrl = function (url) { return value } -var createKarmaMiddleware = function (filesPromise, serveStaticFile, serveFile, - /* config.basePath */ basePath, /* config.urlRoot */ urlRoot, /* config.client */ client, - /* config.customContextFile */ customContextFile, /* config.customDebugFile */ customDebugFile) { +var createKarmaMiddleware = function ( + filesPromise, + serveStaticFile, + serveFile, + injector, + /* config.basePath */ basePath, + /* config.urlRoot */ urlRoot +) { return function (request, response, next) { + // These config values should be up to date on every request + var client = injector.get('config.client') + var customContextFile = injector.get('config.customContextFile') + var customDebugFile = injector.get('config.customDebugFile') + var requestUrl = request.normalizedUrl.replace(/\?.*/, '') // redirect /__karma__ to /__karma__ (trailing slash) @@ -110,13 +122,17 @@ var createKarmaMiddleware = function (filesPromise, serveStaticFile, serveFile, return filesPromise.then(function (files) { var fileServer var requestedFileUrl + log.debug('custom files', customContextFile, customDebugFile) if (isRequestingContextFile && customContextFile) { + log.debug('Serving customContextFile %s', customContextFile) fileServer = serveFile requestedFileUrl = customContextFile } else if (isRequestingDebugFile && customDebugFile) { + log.debug('Serving customDebugFile %s', customDebugFile) fileServer = serveFile requestedFileUrl = customDebugFile } else { + log.debug('Serving static request %s', requestUrl) fileServer = serveStaticFile requestedFileUrl = requestUrl } @@ -197,9 +213,5 @@ var createKarmaMiddleware = function (filesPromise, serveStaticFile, serveFile, } } -createKarmaMiddleware.$inject = ['filesPromise', 'serveStaticFile', 'serveFile', - 'config.basePath', 'config.urlRoot', 'config.client', 'config.customContextFile', - 'config.customDebugFile'] - // PUBLIC API exports.create = createKarmaMiddleware diff --git a/lib/web-server.js b/lib/web-server.js index dc200fda6..1405032c0 100644 --- a/lib/web-server.js +++ b/lib/web-server.js @@ -55,6 +55,7 @@ var createWebServer = function (injector, emitter, fileList) { var proxyMiddlewareInstance = injector.invoke(proxyMiddleware.create) + log.debug('Instantiating middleware') var handler = connect() .use(injector.invoke(runnerMiddleware.create)) .use(injector.invoke(stopperMiddleware.create)) diff --git a/test/unit/middleware/karma.spec.js b/test/unit/middleware/karma.spec.js index 534a33453..ef78829cb 100644 --- a/test/unit/middleware/karma.spec.js +++ b/test/unit/middleware/karma.spec.js @@ -34,13 +34,31 @@ describe('middleware.karma', () => { var handler = serveFile = filesDeferred = nextSpy = response = null + var clientConfig = {foo: 'bar'} + var injector = { + get (val) { + switch (val) { + case 'config.client': + return clientConfig + default: + return null + } + } + } + beforeEach(() => { - var clientConfig = {foo: 'bar'} nextSpy = sinon.spy() response = new HttpResponseMock() filesDeferred = helper.defer() serveFile = createServeFile(fsMock, '/karma/static') - handler = createKarmaMiddleware(filesDeferred.promise, serveFile, null, '/base/path', '/__karma__/', clientConfig) + handler = createKarmaMiddleware( + filesDeferred.promise, + serveFile, + null, + injector, + '/base/path', + '/__karma__/' + ) }) // helpers @@ -92,7 +110,14 @@ describe('middleware.karma', () => { }) it('should serve client.html', (done) => { - handler = createKarmaMiddleware(null, serveFile, null, '/base', '/') + handler = createKarmaMiddleware( + null, + serveFile, + null, + injector, + '/base', + '/' + ) response.once('end', () => { expect(nextSpy).not.to.have.been.called @@ -104,7 +129,14 @@ describe('middleware.karma', () => { }) it('should serve /?id=xxx', (done) => { - handler = createKarmaMiddleware(null, serveFile, null, '/base', '/') + handler = createKarmaMiddleware( + null, + serveFile, + null, + injector, + '/base', + '/' + ) response.once('end', () => { expect(nextSpy).not.to.have.been.called @@ -116,7 +148,14 @@ describe('middleware.karma', () => { }) it('should serve /?x-ua-compatible with replaced values', (done) => { - handler = createKarmaMiddleware(null, serveFile, null, '/base', '/') + handler = createKarmaMiddleware( + null, + serveFile, + null, + injector, + '/base', + '/' + ) response.once('end', () => { expect(nextSpy).not.to.have.been.called @@ -351,4 +390,47 @@ describe('middleware.karma', () => { done() }) }) + + it('should update handle updated configs', (done) => { + let i = 0 + handler = createKarmaMiddleware( + filesDeferred.promise, + serveFile, + null, + { + get (val) { + if (val === 'config.client') { + i++ + if (i === 1) { + return {foo: 'bar'} + } else { + return {foo: 'baz'} + } + } else { + return null + } + } + }, + '/base/path', + '/__karma__/' + ) + + includedFiles([ + new MockFile('/first.js') + ]) + fsMock._touchFile('/karma/static/debug.html', 1, '%CLIENT_CONFIG%') + + response.once('end', () => { + expect(response).to.beServedAs(200, 'window.__karma__.config = {"foo":"bar"};\n') + + response = new HttpResponseMock() + callHandlerWith('/__karma__/debug.html') + response.once('end', () => { + expect(response).to.beServedAs(200, 'window.__karma__.config = {"foo":"baz"};\n') + done() + }) + }) + + callHandlerWith('/__karma__/debug.html') + }) }) From 2b7d703b083f6467dbb3b3c7933a1086cefb7cd3 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 24 Feb 2016 16:29:14 +0100 Subject: [PATCH 10/11] fix(launcher): Allow dynamic browser launches --- lib/launcher.js | 84 +++++++++++++++--------- package.json | 2 +- test/e2e/load.feature | 6 +- test/unit/launcher.spec.js | 131 +++++++++++++++++++++---------------- 4 files changed, 131 insertions(+), 92 deletions(-) diff --git a/lib/launcher.js b/lib/launcher.js index 0d32b1157..aed0a8548 100644 --- a/lib/launcher.js +++ b/lib/launcher.js @@ -1,5 +1,5 @@ var Promise = require('bluebird') -var Batch = require('batch') +var Jobs = require('qjobs') var helper = require('./helper') var log = require('./logger').create('launcher') @@ -25,27 +25,25 @@ var baseBrowserDecoratorFactory = function ( } var Launcher = function (server, emitter, injector) { - var browsers = [] + this._browsers = [] var lastStartTime + var self = this var getBrowserById = function (id) { - for (var i = 0; i < browsers.length; i++) { - if (browsers[i].id === id) { - return browsers[i] + for (var i = 0; i < self._browsers.length; i++) { + if (self._browsers[i].id === id) { + return self._browsers[i] } } return null } - this.launch = function (names, protocol, hostname, port, urlRoot, concurrency) { - var url = protocol + '//' + hostname + ':' + port + urlRoot - var batch = new Batch() - batch.concurrency(concurrency) + this.launchSingle = function (protocol, hostname, port, urlRoot) { + var self = this + return function (name) { + var url = protocol + '//' + hostname + ':' + port + urlRoot - lastStartTime = Date.now() - - names.forEach(function (name) { var locals = { id: ['value', Launcher.generateId()], name: ['value', name], @@ -75,29 +73,26 @@ var Launcher = function (server, emitter, injector) { return } - if (server.loadErrors.length > 0) return [] // TODO(vojta): remove in v1.0 (BC for old launchers) if (!browser.forceKill) { browser.forceKill = function () { - var self = this - + var me = this return new Promise(function (resolve) { - self.kill(resolve) + me.kill(resolve) }) } browser.restart = function () { - var self = this + var me = this this.kill(function () { - self.start(url) + me.start(url) }) } } - batch.push(function (done) { + self.jobs.add(function (args, done) { log.info('Starting browser %s', helper.isDefined(browser.displayName) ? browser.displayName : browser.name) - browser.start(url) browser.on('browser_process_failure', function () { done(browser.error) }) @@ -109,12 +104,34 @@ var Launcher = function (server, emitter, injector) { done(null, browser) }) - }) - browsers.push(browser) - }) + browser.start(url) + }, []) + + self.jobs.run() + self._browsers.push(browser) + } + } + + this.launch = function (names, concurrency) { + log.info('Launching', names, concurrency) + this.jobs = new Jobs({maxConcurrency: concurrency}) - batch.end(function (err) { + var self = this + lastStartTime = Date.now() + + if (server.loadErrors.length === 0) { + names.forEach(function (name) { + injector.invoke(self.launchSingle, self)(name) + }) + } else { + // Empty task to ensure `end` is emitted + this.jobs.add(function (args, done) { + done() + }, []) + } + + this.jobs.on('end', function (err) { log.debug('Finished all browsers') if (err) { @@ -122,16 +139,21 @@ var Launcher = function (server, emitter, injector) { } }) - return browsers + this.jobs.run() + + return self._browsers } this.launch.$inject = [ 'config.browsers', + 'config.concurrency' + ] + + this.launchSingle.$inject = [ 'config.protocol', 'config.hostname', 'config.port', - 'config.urlRoot', - 'config.concurrency' + 'config.urlRoot' ] this.kill = function (id, callback) { @@ -169,24 +191,24 @@ var Launcher = function (server, emitter, injector) { } } - if (!browsers.length) { + if (!self._browsers.length) { return process.nextTick(callback) } - browsers.forEach(function (browser) { + self._browsers.forEach(function (browser) { remaining++ browser.forceKill().then(finish) }) } this.areAllCaptured = function () { - return !browsers.some(function (browser) { + return !self._browsers.some(function (browser) { return !browser.isCaptured() }) } this.markCaptured = function (id) { - browsers.forEach(function (browser) { + self._browsers.forEach(function (browser) { if (browser.id === id) { browser.markCaptured() log.debug('%s (id %s) captured in %d secs', browser.name, browser.id, diff --git a/package.json b/package.json index c4593874b..b0d8e246a 100644 --- a/package.json +++ b/package.json @@ -261,7 +261,6 @@ "Karolis Narkevicius " ], "dependencies": { - "batch": "^0.5.3", "bluebird": "^3.3.0", "body-parser": "^1.12.4", "chokidar": "^1.4.1", @@ -281,6 +280,7 @@ "mime": "^1.3.4", "minimatch": "^3.0.0", "optimist": "^0.6.1", + "qjobs": "^1.1.4", "rimraf": "^2.3.3", "socket.io": "^1.4.5", "source-map": "^0.5.3", diff --git a/test/e2e/load.feature b/test/e2e/load.feature index 865f211a7..cab1c8c30 100644 --- a/test/e2e/load.feature +++ b/test/e2e/load.feature @@ -98,9 +98,5 @@ Feature: Basic Testrunner """ And it fails with like: """ - Cannot load browser "NonExistingBrowser": it is not registered! Perhaps you are missing some plugin\? - """ - And it fails with like: - """ - Found 3 load errors + Found 2 load errors """ diff --git a/test/unit/launcher.spec.js b/test/unit/launcher.spec.js index dfbde5842..366fc16ba 100644 --- a/test/unit/launcher.spec.js +++ b/test/unit/launcher.spec.js @@ -21,11 +21,18 @@ class FakeBrowser { constructor (id, name, baseBrowserDecorator) { this.id = id this.name = name + this.DEFAULT_CMD = { + linux: '/script', + darwin: '/script', + win32: 'script.exe' + } + this.ENV_CMD = 'SCRIPT_BIN' + baseBrowserDecorator(this) FakeBrowser._instances.push(this) sinon.stub(this, 'start', () => { this.state = this.STATE_BEING_CAPTURED - return this.state + this._done() }) stubPromise(this, 'forceKill') sinon.stub(this, 'restart') @@ -36,10 +43,18 @@ class ScriptBrowser { constructor (id, name, baseBrowserDecorator) { this.id = id this.name = name + this.DEFAULT_CMD = { + linux: '/script', + darwin: '/script', + win32: 'script.exe' + } + this.ENV_CMD = 'SCRIPT_BIN' + baseBrowserDecorator(this) ScriptBrowser._instances.push(this) sinon.stub(this, 'start', () => { this.state = this.STATE_BEING_CAPTURED + this._done() }) stubPromise(this, 'forceKill') sinon.stub(this, 'restart') @@ -70,82 +85,82 @@ describe('launcher', () => { describe('Launcher', () => { var emitter var server - var l = emitter = server = null + var config + var l beforeEach(() => { emitter = new events.EventEmitter() server = {'loadErrors': []} + config = { + captureTimeout: 0, + protocol: 'http:', + hostname: 'localhost', + port: 1234, + urlRoot: '/root/' + } var injector = new di.Injector([{ 'launcher:Fake': ['type', FakeBrowser], 'launcher:Script': ['type', ScriptBrowser], 'server': ['value', server], 'emitter': ['value', emitter], - 'config': ['value', {captureTimeout: 0}], + 'config': ['value', config], 'timer': ['factory', createMockTimer] }]) l = new launcher.Launcher(server, emitter, injector) }) describe('launch', () => { - it('should inject and start all browsers', () => { - l.launch(['Fake'], 'http:', 'localhost', 1234, '/root/', 1) + it('should inject and start all browsers', (done) => { + l.launch(['Fake'], 1) var browser = FakeBrowser._instances.pop() - expect(browser.start).to.have.been.calledWith('http://localhost:1234/root/') - expect(browser.id).to.equal(lastGeneratedId) - expect(browser.name).to.equal('Fake') + l.jobs.on('end', () => { + expect(browser.start).to.have.been.calledWith('http://localhost:1234/root/') + expect(browser.id).to.equal(lastGeneratedId) + expect(browser.name).to.equal('Fake') + done() + }) }) - it('should not start when server has load errors', () => { + it('should not start when server has load errors', (done) => { server.loadErrors = ['error'] - l.launch(['Fake'], 'http:', 'localhost', 1234, '/root/', 1) - var browser = FakeBrowser._instances.pop() - expect(browser.start).to.not.have.been.called - expect(browser.id).to.equal(lastGeneratedId) - expect(browser.name).to.equal('Fake') + l.launch(['Fake'], 1) + + l.jobs.on('end', () => { + expect(FakeBrowser._instances).to.be.empty + done() + }) }) - it('should allow launching a script', () => { - l.launch(['/usr/local/bin/special-browser'], 'http:', 'localhost', 1234, '/', 1) + it('should allow launching a script', (done) => { + l.launch(['/usr/local/bin/special-browser'], 1) var script = ScriptBrowser._instances.pop() - expect(script.start).to.have.been.calledWith('http://localhost:1234/') - expect(script.name).to.equal('/usr/local/bin/special-browser') - }) - it('should use the non default host', () => { - l.launch(['Fake'], 'http:', 'whatever', 1234, '/root/', 1) + l.jobs.on('end', () => { + expect(script.start).to.have.been.calledWith('http://localhost:1234/root/') + expect(script.name).to.equal('/usr/local/bin/special-browser') - var browser = FakeBrowser._instances.pop() - expect(browser.start).to.have.been.calledWith('http://whatever:1234/root/') + done() + }) }) - it('should only launch the specified number of browsers at once', () => { - l.launch([ - 'Fake', - 'Fake', - 'Fake' - ], 'http:', 'whatever', 1234, '/root/', 2) - - var b1 = FakeBrowser._instances.pop() - var b2 = FakeBrowser._instances.pop() - var b3 = FakeBrowser._instances.pop() - - expect(b1.start).to.not.have.been.called - expect(b2.start).to.have.been.calledOnce - expect(b3.start).to.have.been.calledOnce + it('should use the non default host', (done) => { + config.hostname = 'whatever' + l.launch(['Fake'], 1) - b1._done() - b2._done() - - expect(b1.start).to.have.been.calledOnce + var browser = FakeBrowser._instances.pop() + l.jobs.on('end', () => { + expect(browser.start).to.have.been.calledWith('http://whatever:1234/root/') + done() + }) }) }) describe('restart', () => { it('should restart the browser', () => { - l.launch(['Fake'], 'http:', 'localhost', 1234, '/root/', 1) + l.launch(['Fake'], 1) var browser = FakeBrowser._instances.pop() var returnedValue = l.restart(lastGeneratedId) @@ -154,14 +169,14 @@ describe('launcher', () => { }) it('should return false if the browser was not launched by launcher (manual)', () => { - l.launch([], 'http:', 'localhost', 1234, '/', 1) + l.launch([], 1) expect(l.restart('manual-id')).to.equal(false) }) }) describe('kill', () => { it('should kill browser with given id', (done) => { - l.launch(['Fake'], 'http:', 'localhost', 1234, '/', 1) + l.launch(['Fake'], 1) var browser = FakeBrowser._instances.pop() l.kill(browser.id, done) @@ -171,7 +186,7 @@ describe('launcher', () => { }) it('should return false if browser does not exist, but still resolve the callback', (done) => { - l.launch(['Fake'], 'http:', 'localhost', 1234, '/', 1) + l.launch(['Fake'], 1) var browser = FakeBrowser._instances.pop() var returnedValue = l.kill('weird-id', done) @@ -180,7 +195,7 @@ describe('launcher', () => { }) it('should not require a callback', (done) => { - l.launch(['Fake'], 'http:', 'localhost', 1234, '/', 1) + l.launch(['Fake'], 1) FakeBrowser._instances.pop() l.kill('weird-id') @@ -190,7 +205,7 @@ describe('launcher', () => { describe('killAll', () => { it('should kill all running processe', () => { - l.launch(['Fake', 'Fake'], 'http:', 'localhost', 1234, '/', 1) + l.launch(['Fake', 'Fake'], 1) l.killAll() var browser = FakeBrowser._instances.pop() @@ -203,7 +218,7 @@ describe('launcher', () => { it('should call callback when all processes killed', () => { var exitSpy = sinon.spy() - l.launch(['Fake', 'Fake'], 'http:', 'localhost', 1234, '/', 1) + l.launch(['Fake', 'Fake'], 1) l.killAll(exitSpy) expect(exitSpy).not.to.have.been.called @@ -234,21 +249,27 @@ describe('launcher', () => { describe('areAllCaptured', () => { it('should return true if only if all browsers captured', () => { - l.launch(['Fake', 'Fake'], 'http:', 'localhost', 1234, '/', 2) + l._browsers = [{ + isCaptured: () => true + }, { + isCaptured: () => false + }] - expect(l.areAllCaptured()).to.equal(false) + expect(l.areAllCaptured()).to.be.equal(false) - l.markCaptured(1) - expect(l.areAllCaptured()).to.equal(false) + l._browsers = [{ + isCaptured: () => true + }, { + isCaptured: () => true + }] - l.markCaptured(2) - expect(l.areAllCaptured()).to.equal(true) + expect(l.areAllCaptured()).to.be.equal(true) }) }) describe('onExit', () => { it('should kill all browsers', (done) => { - l.launch(['Fake', 'Fake'], 'http:', 'localhost', 1234, '/', 1) + l.launch(['Fake', 'Fake'], 1) emitter.emitAsync('exit').then(done) From b35a53c69a9cd5050de3ba1b60b7c432b6ea531d Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Mon, 7 Mar 2016 16:45:45 +0100 Subject: [PATCH 11/11] test(e2e): Increase cucumber test timeouts --- gruntfile.js | 3 ++- test/e2e/support/env.js | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 test/e2e/support/env.js diff --git a/gruntfile.js b/gruntfile.js index 7542e7fd7..5c793b8cb 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -46,7 +46,8 @@ module.exports = function (grunt) { cucumberjs: { options: { steps: 'test/e2e/steps', - format: 'progress' + format: 'progress', + require: 'test/e2e/support/env.js' }, all: 'test/e2e/*.feature', current: { diff --git a/test/e2e/support/env.js b/test/e2e/support/env.js new file mode 100644 index 000000000..8eb4a74c6 --- /dev/null +++ b/test/e2e/support/env.js @@ -0,0 +1,5 @@ +var configure = function () { + this.setDefaultTimeout(60 * 1000) +} + +module.exports = configure