Skip to content

Commit 3e55175

Browse files
shellscapesindresorhus
authored andcommittedFeb 20, 2017
Spawn Mocha instead of using its API (#151)
1 parent 212def2 commit 3e55175

11 files changed

+139
-277
lines changed
 

‎.travis.yml

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
sudo: false
22
language: node_js
33
node_js:
4-
- '6'
54
- '4'
6-
- '0.12'
7-
- '0.10'
5+
- '6'
6+
- '7'

‎index.js

+52-69
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,55 @@
11
'use strict';
2-
var domain = require('domain'); // eslint-disable-line no-restricted-modules
3-
var gutil = require('gulp-util');
4-
var through = require('through');
5-
var Mocha = require('mocha');
6-
var plur = require('plur');
7-
var reqCwd = require('req-cwd');
82

9-
module.exports = function (opts) {
10-
opts = opts || {};
11-
12-
var mocha = new Mocha(opts);
13-
var cache = {};
14-
15-
for (var key in require.cache) { // eslint-disable-line guard-for-in
16-
cache[key] = true;
17-
}
18-
19-
function clearCache() {
20-
for (var key in require.cache) {
21-
if (!cache[key] && !/\.node$/.test(key)) {
22-
delete require.cache[key];
23-
}
24-
}
25-
}
26-
27-
if (Array.isArray(opts.require) && opts.require.length) {
28-
opts.require.forEach(function (x) {
29-
reqCwd(x);
30-
});
31-
}
32-
33-
return through(function (file) {
34-
mocha.addFile(file.path);
35-
this.queue(file);
36-
}, function () {
37-
var self = this;
38-
var d = domain.create();
39-
var runner;
40-
41-
function handleException(err) {
42-
if (runner) {
43-
runner.uncaught(err);
44-
} else {
45-
clearCache();
46-
self.emit('error', new gutil.PluginError('gulp-mocha', err, {
47-
stack: err.stack,
48-
showStack: true
49-
}));
50-
}
51-
}
52-
53-
d.on('error', handleException);
54-
d.run(function () {
55-
try {
56-
runner = mocha.run(function (errCount) {
57-
clearCache();
58-
59-
if (errCount > 0) {
60-
self.emit('error', new gutil.PluginError('gulp-mocha', errCount + ' ' + plur('test', errCount) + ' failed.', {
61-
showStack: false
62-
}));
63-
}
64-
65-
self.emit('end');
66-
});
67-
} catch (err) {
68-
handleException(err);
69-
}
70-
});
71-
});
3+
const dargs = require('dargs');
4+
const execa = require('execa');
5+
const gutil = require('gulp-util');
6+
const through = require('through2');
7+
8+
module.exports = options => {
9+
const defaults = {colors: true, suppress: false};
10+
11+
options = Object.assign(defaults, options);
12+
13+
if (Object.prototype.toString.call(options.globals) === '[object Array]') {
14+
// typically wouldn't modify passed options, but mocha requires a comma-
15+
// separated list of names, http://mochajs.org/#globals-names, whereas dargs
16+
// will treat arrays differently.
17+
options.globals = options.globals.join(',');
18+
}
19+
20+
// exposing args for testing
21+
const args = dargs(options, {excludes: ['suppress'], ignoreFalse: true});
22+
const files = [];
23+
24+
function aggregate(file, encoding, done) {
25+
if (file.isNull()) {
26+
return done(null, file);
27+
}
28+
29+
if (file.isStream()) {
30+
return done(new gutil.PluginError('gulp-mocha', 'Streaming not supported'));
31+
}
32+
33+
files.push(file.path);
34+
35+
return done();
36+
}
37+
38+
function flush(done) {
39+
execa('mocha', files.concat(args))
40+
.then(result => {
41+
if (!options.suppress) {
42+
process.stdout.write(result.stdout);
43+
}
44+
45+
this.emit('result', result);
46+
done();
47+
})
48+
.catch(err => {
49+
this.emit('error', new gutil.PluginError('gulp-mocha', err));
50+
done();
51+
});
52+
}
53+
54+
return through.obj(aggregate, flush);
7255
};

‎package.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"url": "sindresorhus.com"
1111
},
1212
"engines": {
13-
"node": ">=0.10.0"
13+
"node": ">=4"
1414
},
1515
"scripts": {
1616
"test": "xo && mocha"
@@ -33,12 +33,11 @@
3333
"tap"
3434
],
3535
"dependencies": {
36+
"dargs": "^5.1.0",
37+
"execa": "^0.6.0",
3638
"gulp-util": "^3.0.0",
3739
"mocha": "^3.0.0",
38-
"plur": "^2.1.0",
39-
"req-cwd": "^1.0.1",
40-
"temp": "^0.8.3",
41-
"through": "^2.3.4"
40+
"through2": "^2.0.3"
4241
},
4342
"devDependencies": {
4443
"xo": "*"
@@ -47,6 +46,7 @@
4746
"envs": [
4847
"node",
4948
"mocha"
50-
]
49+
],
50+
"space": true
5151
}
5252
}

‎readme.md

+8-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ $ npm install --save-dev gulp-mocha
2626
const gulp = require('gulp');
2727
const mocha = require('gulp-mocha');
2828

29-
gulp.task('default', () =>
29+
gulp.task('default', () =>
3030
gulp.src('test.js', {read: false})
3131
// gulp-mocha needs filepaths so you can't have any plugins before it
3232
.pipe(mocha({reporter: 'nyan'}))
@@ -42,6 +42,10 @@ gulp.task('default', () =>
4242

4343
#### options
4444

45+
gulp-mocha will pass any options defined directly to the `mocha` binary. That
46+
means you have every [command line option](http://mochajs.org/#usage) available
47+
by default. Listed below are some of the more commonly used options:
48+
4549
##### ui
4650

4751
Type: `string`<br>
@@ -80,12 +84,12 @@ Default: `false`
8084

8185
Bail on the first test failure.
8286

83-
##### ignoreLeaks
87+
##### checkLeaks
8488

8589
Type: `boolean`<br>
8690
Default: `false`
8791

88-
Ignore global leaks.
92+
Check for global variable leaks.
8993

9094
##### grep
9195

@@ -107,7 +111,7 @@ Require custom modules before tests are run.
107111
If your test suite is not exiting it might be because you still have a lingering callback, most often caused by an open database connection. You should close this connection or do the following:
108112

109113
```js
110-
gulp.task('default', () =>
114+
gulp.task('default', () =>
111115
gulp.src('test.js')
112116
.pipe(mocha())
113117
.once('error', () => {

‎test/fixtures/fixture-async.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
var assert = require('assert');
44

55
it('should fail after timeout', function (done) {
6-
setTimeout(function () {
7-
assert(false);
8-
}, 10);
6+
setTimeout(function () {
7+
assert(false);
8+
}, 10);
99
});

‎test/fixtures/fixture-fail.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
var assert = require('assert');
33

44
it('should fail', function () {
5-
assert(false);
5+
assert(false);
66
});

‎test/fixtures/fixture-pass.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
var assert = require('assert');
33

44
it('should pass', function () {
5-
assert(true);
5+
assert(true);
66
});

‎test/fixtures/fixture-throws-uncaught.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
var assert = require('assert');
33

44
it('throws after timeout', function (done) {
5-
setTimeout(function () {
6-
throw new Error('Exception in delayed function');
7-
}, 10);
5+
setTimeout(function () {
6+
throw new Error('Exception in delayed function');
7+
}, 10);
88
});

‎test/fixtures/fixture-throws.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
var assert = require('assert');
33

44
it('contains syntax errors', function () {
5-
assert false;
5+
assert false;
66
});

‎test/require-test.js

-49
This file was deleted.

‎test/test.js

+62-137
Original file line numberDiff line numberDiff line change
@@ -1,140 +1,65 @@
11
'use strict';
2-
var assert = require('assert');
3-
var gutil = require('gulp-util');
4-
var mocha = require('../');
52

6-
var out = process.stdout.write.bind(process.stdout);
7-
var err = process.stderr.write.bind(process.stderr);
8-
9-
afterEach(function () {
10-
process.stdout.write = out;
11-
process.stderr.write = err;
12-
});
13-
14-
it('should run unit test and pass', function (cb) {
15-
var stream = mocha();
16-
17-
process.stdout.write = function (str) {
18-
if (/1 passing/.test(str)) {
19-
assert(true);
20-
cb();
21-
}
22-
};
23-
24-
stream.write(new gutil.File({path: './test/fixtures/fixture-pass.js'}));
25-
stream.end();
26-
});
27-
28-
it('should run unit test and fail', function (cb) {
29-
var stream = mocha();
30-
31-
process.stdout.write = function (str) {
32-
if (/1 failing/.test(str)) {
33-
assert(true);
34-
cb();
35-
}
36-
};
37-
38-
stream.once('error', function () {});
39-
stream.write(new gutil.File({path: './test/fixtures/fixture-fail.js'}));
40-
stream.end();
41-
});
42-
43-
it('should call the callback right after end', function (cb) {
44-
var stream = mocha();
45-
46-
stream.once('end', function () {
47-
assert(true);
48-
cb();
49-
});
50-
51-
stream.end();
52-
});
53-
54-
it('should clear cache after successful run', function (done) {
55-
var stream = mocha();
56-
57-
stream.once('end', function () {
58-
for (var key in require.cache) {
59-
if (/fixture-pass/.test(key.toString())) {
60-
done(new Error('require cache still contained: ' + key));
61-
return;
62-
}
63-
}
64-
65-
done();
66-
});
67-
68-
stream.write(new gutil.File({path: './test/fixtures/fixture-pass.js'}));
69-
stream.end();
70-
});
71-
72-
it('should clear cache after failing run', function (done) {
73-
var stream = mocha();
74-
75-
stream.once('error', function () {
76-
for (var key in require.cache) {
77-
if (/fixture-fail/.test(key.toString())) {
78-
done(new Error('require cache still contained: ' + key));
79-
return;
80-
}
81-
}
82-
83-
done();
84-
});
85-
86-
stream.write(new gutil.File({path: './test/fixtures/fixture-fail.js'}));
87-
stream.end();
88-
});
89-
90-
it('should clear cache after mocha threw', function (done) {
91-
var stream = mocha();
92-
93-
stream.once('error', function () {
94-
for (var key in require.cache) {
95-
if (/fixture-pass/.test(key.toString()) || /fixture-throws/.test(key.toString())) {
96-
done(new Error('require cache still contained: ' + key));
97-
return;
98-
}
99-
}
100-
101-
done();
102-
});
103-
stream.write(new gutil.File({path: './test/fixtures/fixture-pass.js'}));
104-
stream.write(new gutil.File({path: './test/fixtures/fixture-throws.js'}));
105-
stream.end();
106-
});
107-
108-
it('should clear cache after mocha threw uncaught exception', function (done) {
109-
var stream = mocha();
110-
111-
stream.once('error', function () {
112-
for (var key in require.cache) {
113-
if (/fixture-pass/.test(key.toString()) || /fixture-throws/.test(key.toString())) {
114-
done(new Error('require cache still contained: ' + key));
115-
return;
116-
}
117-
}
118-
119-
done();
120-
});
121-
stream.write(new gutil.File({path: './test/fixtures/fixture-pass.js'}));
122-
stream.write(new gutil.File({path: './test/fixtures/fixture-throws-uncaught.js'}));
123-
stream.end();
124-
});
125-
126-
it('should pass async AssertionError to mocha', function (done) {
127-
var stream = mocha();
128-
129-
process.stdout.write = function (str) {
130-
if (/throws after timeout/.test(str)) {
131-
done(new Error('mocha timeout not expected'));
132-
} else if (/Uncaught AssertionError: false == true/.test(str)) {
133-
done();
134-
}
135-
};
136-
137-
stream.once('error', function () {});
138-
stream.write(new gutil.File({path: './test/fixtures/fixture-async.js'}));
139-
stream.end();
3+
const assert = require('assert');
4+
const fs = require('fs');
5+
const path = require('path');
6+
const gutil = require('gulp-util');
7+
const mocha = require('../');
8+
9+
function fixture(name) {
10+
let fileName = path.join(__dirname, 'fixtures', name);
11+
12+
return new gutil.File({
13+
path: fileName,
14+
contents: fs.existsSync(fileName) ? fs.readFileSync(fileName) : null
15+
});
16+
}
17+
18+
describe('mocha()', () => {
19+
it('should run unit test and pass', done => {
20+
let stream = mocha({suppress: true});
21+
22+
stream.once('result', result => {
23+
assert(/1 passing/.test(result.stdout));
24+
done();
25+
});
26+
stream.write(fixture('fixture-pass.js'));
27+
stream.end();
28+
});
29+
30+
it('should run unit test and fail', done => {
31+
let stream = mocha({suppress: true});
32+
33+
stream.once('error', function (err) {
34+
assert(/1 failing/.test(err.stdout));
35+
done();
36+
});
37+
stream.write(fixture('fixture-fail.js'));
38+
stream.end();
39+
});
40+
41+
it('should pass async AssertionError to mocha', function (done) {
42+
let stream = mocha({suppress: true});
43+
44+
stream.once('error', function (err) {
45+
let throws = /throws after timeout/.test(err.stdout);
46+
let uncaught = /Uncaught AssertionError: false == true/.test(err.stdout);
47+
48+
assert(throws || uncaught);
49+
done();
50+
});
51+
stream.write(fixture('fixture-async.js'));
52+
stream.end();
53+
});
54+
55+
it('should not suppress output', done => {
56+
let stream = mocha();
57+
58+
stream.once('result', result => {
59+
assert(/should pass/.test(result.stdout));
60+
done();
61+
});
62+
stream.write(fixture('fixture-pass.js'));
63+
stream.end();
64+
});
14065
});

0 commit comments

Comments
 (0)
Please sign in to comment.