mochajs / mocha

☕️ simple, flexible, fun javascript test framework for node.js & the browser
https://mochajs.org
MIT License
22.63k stars 3.02k forks source link

🚀 Feature: Support multiple reporters in browser #3902

Open letsgotomars opened 5 years ago

letsgotomars commented 5 years ago

Is your feature request related to a problem or a nice-to-have?? This is a 'nice-to-have'

I think it's awesome that mocha supports running in the browser!

I would like mocha be able to support multiple reporters for the browser - mainly for using 'json-stream' with 'html'. Currently you can only specify one reporter.

Describe the solution you'd like

My first thought would be to have mocha.setup() be able to accept an array reporters instead of just a single string For example:

    mocha.setup({
        ui: 'bdd',
        reporter: ['html', 'json-stream']
    });

Another solution would be to have json-stream as an additional option:

    mocha.setup({
        ui: 'bdd',
        reporter: 'html',
        jsonStream: true,
    });

As a side note I have a one-line hack working in 'mocha.js' so I know it's definitely possible

thePunderWoman commented 5 years ago

I would love the former option, especially for dealing with code coverage, nyc, and artifact output. I want my CI runs to show the results as they are running but also output to an xml file. I've tried other hacky npm packages, like mocha-multi, with mixed results and it would be nice if this was first party.

letsgotomars commented 5 years ago

@janiukjf code coverage is exactly why we did this modification. We have a tool that runs front-end mocha tests on istanbul instrumented code and then displays the test results using the Mocha 'html' reporter (with some custom dom manipulation). However the tool also hooks into the console logs from 'json-stream' to detect when tests are finished. When it detects the tests are finished it then generates nyc html coverage files and appends a link to those files in the header of the Mocha 'html' report (the user can also optionally download an lcov file).

This allows users to run front-end mocha tests and immediately be able to see the test results and coverage all in one place. Attached is a screenshot of the tool after a test run.

Thought I would share this use-case to demonstrate that there could be a lot of utility to be potentially gained with this feature.

image

antomor commented 4 years ago

Any news on it? @letsgotomars could you share the one line hack necessary to achieve such result?

letsgotomars commented 4 years ago

Sure - I modified a large bundled mocha.js script that I got from a CDN. Sorry I can't remember the specific version we used in our tool. Here is the line I modified:

    Mocha.prototype.run = function(fn) {
      if (this.files.length) {
        this.loadFiles();
      }
      var suite = this.suite;
      var options = this.options;
      options.files = this.files;
      var runner = new exports.Runner(suite, options.delay);
      createStatsCollector(runner);
      var reporter = new this._reporter(runner, options);
      // ===== < CUSTOM MOD > =====
      // Run 'json-stream' reporter always
      if (this._reporter != builtinReporters['JSONStream']) builtinReporters['JSONStream'](runner, options);
      // ===== </ CUSTOM MOD > =====
      runner.ignoreLeaks = options.ignoreLeaks !== false;
      runner.fullStackTrace = options.fullStackTrace;
      runner.asyncOnly = options.asyncOnly;
      runner.allowUncaught = options.allowUncaught;
      runner.forbidOnly = options.forbidOnly;
      runner.forbidPending = options.forbidPending;
      if (options.grep) {
        runner.grep(options.grep, options.invert);
      }
      if (options.globals) {
        runner.globals(options.globals);
      }
      if (options.growl) {
        this._growl(runner);
      }
      if (options.useColors !== undefined) {
        exports.reporters.Base.useColors = options.useColors;
      }
      exports.reporters.Base.inlineDiffs = options.useInlineDiffs;
      exports.reporters.Base.hideDiff = options.hideDiff;

      function done(failures) {
        fn = fn || utils.noop;
        if (reporter.done) {
          reporter.done(failures, fn);
        } else {
          fn(failures);
        }
      }

      return runner.run(done);
    };
letsgotomars commented 4 years ago

Also I made another one-liner change here:

    Progress.prototype.update = function(n) {
      // ===== < CUSTOM MOD > =====
      // Provide hook into mocha testing progress
      window.mocha.percentComplete = n;
      // ===== </ CUSTOM MOD > =====
      this.percent = n;
      return this;
    };