blob: 914d7417b27be142be0a73311d3057bfeee2b204 [file] [log] [blame]
/**
* Runner middleware is responsible for communication with `karma run`.
*
* It basically triggers a test run and streams stdout back.
*/
const _ = require('lodash')
const path = require('path')
const helper = require('../helper')
const log = require('../logger').create()
const constant = require('../constants')
const json = require('body-parser').json()
// TODO(vojta): disable when single-run mode
function createRunnerMiddleware (emitter, fileList, capturedBrowsers, reporter, executor,
/* config.protocol */ protocol, /* config.hostname */ hostname, /* config.port */
port, /* config.urlRoot */ urlRoot, config) {
helper.saveOriginalArgs(config)
return function (request, response, next) {
if (request.url !== '/__run__' && request.url !== urlRoot + 'run') {
return next()
}
log.debug('Execution (fired by runner)')
response.writeHead(200)
if (!capturedBrowsers.length) {
const url = `${protocol}//${hostname}:${port}${urlRoot}`
return response.end(`No captured browser, open ${url}\n`)
}
json(request, response, function () {
if (!capturedBrowsers.areAllReady([])) {
response.write('Waiting for previous execution...\n')
}
const data = request.body
emitter.once('run_start', function () {
const responseWrite = response.write.bind(response)
responseWrite.colors = data.colors
reporter.addAdapter(responseWrite)
// clean up, close runner response
emitter.once('run_complete', function (browsers, results) {
reporter.removeAdapter(responseWrite)
const emptyTestSuite = (results.failed + results.success) === 0 ? 0 : 1
response.end(constant.EXIT_CODE + emptyTestSuite + results.exitCode)
})
})
helper.restoreOriginalArgs(config)
if (_.isEmpty(data.args)) {
log.debug('Ignoring empty client.args from run command')
} else if ((_.isArray(data.args) && _.isArray(config.client.args)) ||
(_.isPlainObject(data.args) && _.isPlainObject(config.client.args))) {
log.debug('Merging client.args with ', data.args)
config.client.args = _.merge(config.client.args, data.args)
} else {
log.warn('Replacing client.args with ', data.args, ' as their types do not match.')
config.client.args = data.args
}
let fullRefresh = true
if (helper.isArray(data.changedFiles)) {
data.changedFiles.forEach(function (filepath) {
fileList.changeFile(path.resolve(config.basePath, filepath))
fullRefresh = false
})
}
if (helper.isArray(data.addedFiles)) {
data.addedFiles.forEach(function (filepath) {
fileList.addFile(path.resolve(config.basePath, filepath))
fullRefresh = false
})
}
if (helper.isArray(data.removedFiles)) {
data.removedFiles.forEach(function (filepath) {
fileList.removeFile(path.resolve(config.basePath, filepath))
fullRefresh = false
})
}
if (fullRefresh && data.refresh !== false) {
log.debug('Refreshing all the files / patterns')
fileList.refresh().then(function () {
// Wait for the file list refresh to complete before starting test run,
// otherwise the context.html generation might not see new/updated files.
if (!config.autoWatch) {
executor.schedule()
}
})
} else {
executor.schedule()
}
})
}
}
createRunnerMiddleware.$inject = ['emitter', 'fileList', 'capturedBrowsers', 'reporter', 'executor',
'config.protocol', 'config.hostname', 'config.port', 'config.urlRoot', 'config']
// PUBLIC API
exports.create = createRunnerMiddleware