41

I may be missing something extremely obvious but I can't get gulp-mocha to catch errors, causing my gulp watch task to end everytime I have a failing test.

It's a very simple set up:

gulp.task("watch", ["build"], function () {
  gulp.watch([paths.scripts, paths.tests], ["test"]);
});

gulp.task("test", function() {
  return gulp.src(paths.tests)
    .pipe(mocha({ reporter: "spec" }).on("error", gutil.log));
});

Alternatively, putting the handler on the entire stream also gives the same problem:

gulp.task("test", function() {
  return gulp.src(paths.tests)
    .pipe(mocha({ reporter: "spec" }))
    .on("error", gutil.log);
});

I've also tried using plumber, combine and gulp-batch to no avail, so I guess I'm overlooking something trivial.

Gist: http://gist.github.com/RoyJacobs/b518ebac117e95ff1457

Roy Jacobs
  • 602
  • 1
  • 5
  • 11
  • Where is the `mocha` symbol coming from in your code? (What defines it?) – Louis Feb 06 '14 at 12:17
  • It's `mocha = require("gulp-mocha")` – Roy Jacobs Feb 06 '14 at 12:58
  • If the failing test is an asynchronous test, then please disable all asynchronous tests that fail (you can comment them out), and add a **synchronous** test that fails (assert that `true === false` for instance). Is the problem still present after this modification? – Louis Feb 06 '14 at 13:10
  • Yes, the entire test suite consists of a single test containing just a simple assert. I've provided a reproduction gist here: https://gist.github.com/RoyJacobs/b518ebac117e95ff1457 – Roy Jacobs Feb 06 '14 at 14:07
  • I was thinking there might be a problem between Mocha's error handling and gulp's (because I've [seen it](https://stackoverflow.com/questions/20561218/assertion-in-event-brake-down-mocha-when-run-programmatically/20566300#20566300) happen between Mocha and other tools) but it does not seem to be the case here. – Louis Feb 06 '14 at 17:22

2 Answers2

67

You need to ignore 'error' and always emit 'end' to make 'gulp.watch' work.

function handleError(err) {
  console.log(err.toString());
  this.emit('end');
}

gulp.task("test", function() {
  return gulp.src(paths.tests)
    .pipe(mocha({ reporter: "spec" })
    .on("error", handleError));
});

This makes 'gulp test' to always return '0' which is problematic for Continuous Integration, but I think we have no choice at this time.

Shuhei Kagawa
  • 4,752
  • 1
  • 33
  • 31
  • This is awesome. I hated that my gulp stream was ending each time I was writing typos in SCSS – xyhhx Mar 29 '15 at 02:53
  • Any solution for the gulp test returning 0 part? Still the best solution, in spite of this minor drawback... :) Thank you!!! – Metagrapher Apr 29 '15 at 13:01
41

Expanding on Shuhei Kagawa's answer..

emitting end will prevent gulp exiting due to the uncaught error being converted into an exception.

Set a watching var to track whether you are running test through watch, then exit or not depending on whether you are developing or running CI.

var watching = false;

function onError(err) {
  console.log(err.toString());
  if (watching) {
    this.emit('end');
  } else {
    // if you want to be really specific
    process.exit(1);
  }
}

gulp.task("test", function() {
  return gulp.src(paths.tests)
    .pipe(mocha({ reporter: "spec" }).on("error", onError));
});

gulp.task("watch", ["build"], function () {
  watching = true;
  gulp.watch([paths.tests], ["test"]);
});

This can then be used for development and CI

callum
  • 34,206
  • 35
  • 106
  • 163
abovethewater
  • 471
  • 4
  • 5