runner.js 3.6 KB

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