json.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. 'use strict';
  2. /**
  3. * @module JSON
  4. */
  5. /**
  6. * Module dependencies.
  7. */
  8. var Base = require('./base');
  9. var constants = require('../runner').constants;
  10. var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
  11. var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
  12. var EVENT_TEST_END = constants.EVENT_TEST_END;
  13. var EVENT_RUN_END = constants.EVENT_RUN_END;
  14. var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
  15. /**
  16. * Expose `JSON`.
  17. */
  18. exports = module.exports = JSONReporter;
  19. /**
  20. * Initialize a new `JSON` reporter.
  21. *
  22. * @public
  23. * @class JSON
  24. * @memberof Mocha.reporters
  25. * @extends Mocha.reporters.Base
  26. * @param {Runner} runner
  27. */
  28. function JSONReporter(runner) {
  29. Base.call(this, runner);
  30. var self = this;
  31. var tests = [];
  32. var pending = [];
  33. var failures = [];
  34. var passes = [];
  35. runner.on(EVENT_TEST_END, function(test) {
  36. tests.push(test);
  37. });
  38. runner.on(EVENT_TEST_PASS, function(test) {
  39. passes.push(test);
  40. });
  41. runner.on(EVENT_TEST_FAIL, function(test) {
  42. failures.push(test);
  43. });
  44. runner.on(EVENT_TEST_PENDING, function(test) {
  45. pending.push(test);
  46. });
  47. runner.once(EVENT_RUN_END, function() {
  48. var obj = {
  49. stats: self.stats,
  50. tests: tests.map(clean),
  51. pending: pending.map(clean),
  52. failures: failures.map(clean),
  53. passes: passes.map(clean)
  54. };
  55. runner.testResults = obj;
  56. process.stdout.write(JSON.stringify(obj, null, 2));
  57. });
  58. }
  59. /**
  60. * Return a plain-object representation of `test`
  61. * free of cyclic properties etc.
  62. *
  63. * @private
  64. * @param {Object} test
  65. * @return {Object}
  66. */
  67. function clean(test) {
  68. var err = test.err || {};
  69. if (err instanceof Error) {
  70. err = errorJSON(err);
  71. }
  72. return {
  73. title: test.title,
  74. fullTitle: test.fullTitle(),
  75. duration: test.duration,
  76. currentRetry: test.currentRetry(),
  77. err: cleanCycles(err)
  78. };
  79. }
  80. /**
  81. * Replaces any circular references inside `obj` with '[object Object]'
  82. *
  83. * @private
  84. * @param {Object} obj
  85. * @return {Object}
  86. */
  87. function cleanCycles(obj) {
  88. var cache = [];
  89. return JSON.parse(
  90. JSON.stringify(obj, function(key, value) {
  91. if (typeof value === 'object' && value !== null) {
  92. if (cache.indexOf(value) !== -1) {
  93. // Instead of going in a circle, we'll print [object Object]
  94. return '' + value;
  95. }
  96. cache.push(value);
  97. }
  98. return value;
  99. })
  100. );
  101. }
  102. /**
  103. * Transform an Error object into a JSON object.
  104. *
  105. * @private
  106. * @param {Error} err
  107. * @return {Object}
  108. */
  109. function errorJSON(err) {
  110. var res = {};
  111. Object.getOwnPropertyNames(err).forEach(function(key) {
  112. res[key] = err[key];
  113. }, err);
  114. return res;
  115. }
  116. JSONReporter.description = 'single JSON object';