Yang Guo | 4fd355c | 2019-09-19 08:59:03 | [diff] [blame^] | 1 | /** |
| 2 | * Runner middleware is responsible for communication with `karma run`. |
| 3 | * |
| 4 | * It basically triggers a test run and streams stdout back. |
| 5 | */ |
| 6 | |
| 7 | const _ = require('lodash') |
| 8 | const path = require('path') |
| 9 | const helper = require('../helper') |
| 10 | const log = require('../logger').create() |
| 11 | const constant = require('../constants') |
| 12 | const json = require('body-parser').json() |
| 13 | |
| 14 | // TODO(vojta): disable when single-run mode |
| 15 | function createRunnerMiddleware (emitter, fileList, capturedBrowsers, reporter, executor, |
| 16 | /* config.protocol */ protocol, /* config.hostname */ hostname, /* config.port */ |
| 17 | port, /* config.urlRoot */ urlRoot, config) { |
| 18 | helper.saveOriginalArgs(config) |
| 19 | return function (request, response, next) { |
| 20 | if (request.url !== '/__run__' && request.url !== urlRoot + 'run') { |
| 21 | return next() |
| 22 | } |
| 23 | |
| 24 | log.debug('Execution (fired by runner)') |
| 25 | response.writeHead(200) |
| 26 | |
| 27 | if (!capturedBrowsers.length) { |
| 28 | const url = `${protocol}//${hostname}:${port}${urlRoot}` |
| 29 | return response.end(`No captured browser, open ${url}\n`) |
| 30 | } |
| 31 | |
| 32 | json(request, response, function () { |
| 33 | if (!capturedBrowsers.areAllReady([])) { |
| 34 | response.write('Waiting for previous execution...\n') |
| 35 | } |
| 36 | |
| 37 | const data = request.body |
| 38 | emitter.once('run_start', function () { |
| 39 | const responseWrite = response.write.bind(response) |
| 40 | responseWrite.colors = data.colors |
| 41 | reporter.addAdapter(responseWrite) |
| 42 | |
| 43 | // clean up, close runner response |
| 44 | emitter.once('run_complete', function (browsers, results) { |
| 45 | reporter.removeAdapter(responseWrite) |
| 46 | const emptyTestSuite = (results.failed + results.success) === 0 ? 0 : 1 |
| 47 | response.end(constant.EXIT_CODE + emptyTestSuite + results.exitCode) |
| 48 | }) |
| 49 | }) |
| 50 | |
| 51 | helper.restoreOriginalArgs(config) |
| 52 | if (_.isEmpty(data.args)) { |
| 53 | log.debug('Ignoring empty client.args from run command') |
| 54 | } else if ((_.isArray(data.args) && _.isArray(config.client.args)) || |
| 55 | (_.isPlainObject(data.args) && _.isPlainObject(config.client.args))) { |
| 56 | log.debug('Merging client.args with ', data.args) |
| 57 | config.client.args = _.merge(config.client.args, data.args) |
| 58 | } else { |
| 59 | log.warn('Replacing client.args with ', data.args, ' as their types do not match.') |
| 60 | config.client.args = data.args |
| 61 | } |
| 62 | |
| 63 | let fullRefresh = true |
| 64 | |
| 65 | if (helper.isArray(data.changedFiles)) { |
| 66 | data.changedFiles.forEach(function (filepath) { |
| 67 | fileList.changeFile(path.resolve(config.basePath, filepath)) |
| 68 | fullRefresh = false |
| 69 | }) |
| 70 | } |
| 71 | |
| 72 | if (helper.isArray(data.addedFiles)) { |
| 73 | data.addedFiles.forEach(function (filepath) { |
| 74 | fileList.addFile(path.resolve(config.basePath, filepath)) |
| 75 | fullRefresh = false |
| 76 | }) |
| 77 | } |
| 78 | |
| 79 | if (helper.isArray(data.removedFiles)) { |
| 80 | data.removedFiles.forEach(function (filepath) { |
| 81 | fileList.removeFile(path.resolve(config.basePath, filepath)) |
| 82 | fullRefresh = false |
| 83 | }) |
| 84 | } |
| 85 | |
| 86 | if (fullRefresh && data.refresh !== false) { |
| 87 | log.debug('Refreshing all the files / patterns') |
| 88 | fileList.refresh().then(function () { |
| 89 | // Wait for the file list refresh to complete before starting test run, |
| 90 | // otherwise the context.html generation might not see new/updated files. |
| 91 | if (!config.autoWatch) { |
| 92 | executor.schedule() |
| 93 | } |
| 94 | }) |
| 95 | } else { |
| 96 | executor.schedule() |
| 97 | } |
| 98 | }) |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | createRunnerMiddleware.$inject = ['emitter', 'fileList', 'capturedBrowsers', 'reporter', 'executor', |
| 103 | 'config.protocol', 'config.hostname', 'config.port', 'config.urlRoot', 'config'] |
| 104 | |
| 105 | // PUBLIC API |
| 106 | exports.create = createRunnerMiddleware |