Skip to content

Commit 5fc73c2

Browse files
committed
adding iterations array support, modifying JUNIT_REPORT_PATH feature to insert taskNum before .xml, adding docs
1 parent 7ae14d9 commit 5fc73c2

File tree

11 files changed

+220
-101
lines changed

11 files changed

+220
-101
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,8 @@ node_modules
2626

2727

2828
# Webstorm IDE metadata directory
29-
.idea
29+
.idea
30+
31+
# test report files
32+
test/report/*.xml*
33+
test/report/*.log

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,53 @@ gulp.task('test-custom-mocha', function() {
8080
- flags: mocha flags (default: none)
8181
- liveOutput: print output direct to console
8282
- errorSummary: show error summary (default: true)
83+
- iterations: Array, see below
84+
85+
### Iterations
86+
87+
If you want to run parallel processes based on criteria other than files, use an iterations array.
88+
89+
The iterations array should contain whatever "Options" (see above) you wish to override for a given iteration.
90+
91+
The easiest to envision example would be:
92+
* your test suite names are annotated as: @groupA@, @groupB@, @groupC@, and so on
93+
* these groupings are spread across files, where a file may contain one or more suite of a given group
94+
* you want to spawn a mocha process for each grouping
95+
96+
To achieve, you would specify an iterations array where each entry uses a different mocha grep. E.g. the task
97+
example "test-mocha-opts-parallel" in this project's `gulpfile.js`.
98+
99+
```javascript
100+
gulp.task('test-mocha-opts-parallel', function () {
101+
function setEnv(envs) {
102+
var env = process.env;
103+
env = _.clone(env);
104+
env = _.merge(env, envs, {JUNIT_REPORT_PATH: path.resolve(__dirname, 'test/report/report.xml')});
105+
return env;
106+
}
107+
var opts = {
108+
concurrency: 3,
109+
flags: {R: 'mocha-jenkins-reporter'},
110+
iterations: [{
111+
env: setEnv({NODE_ENV: 'groupa'}),
112+
flags: {grep: "@groupA@"}
113+
}, {
114+
env: setEnv({NODE_ENV: 'groupb'}),
115+
flags: {grep: "@groupB@"}
116+
}, {
117+
env: setEnv({NODE_ENV: 'groupc'}),
118+
flags: {grep: "@groupC@"}
119+
}]
120+
};
121+
var mocha = mochaStream(opts);
122+
gulp.src('test/group/*-specs.js')
123+
.pipe(mocha);
124+
});
125+
```
126+
127+
Another use case might be if you are driving browser/device automation, and you want to run the same set of files
128+
in parallel on several browser/device combinations.
129+
83130
## Todo
84131

85132
- concatenate mocha status at the end

gulpfile.js

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
var gulp = require('gulp'),
44
mochaStream = require('./lib').mochaStream,
5-
mochaOptsStream = require('./lib').mochaOptsStream,
65
SpawnMocha = require('./lib').SpawnMocha,
76
_ = require('lodash'),
87
through = require('through'),
98
Q = require('q'),
109
runSequence = Q.denodeify(require('run-sequence')),
1110
assert = require('assert'),
1211
File = require('vinyl'),
12+
path = require('path'),
1313
from = require('from');
1414

1515
function customMocha(opts) {
@@ -86,12 +86,6 @@ gulp.task('test-live-output', function () {
8686
.pipe(mocha);
8787
});
8888

89-
gulp.task('test-mocha-opts-parallel', function () {
90-
var mocha = mochaOptsStream({liveOutput: true, concurrency: 1});
91-
gulp.src('test/*-specs.js')
92-
.pipe(mocha);
93-
});
94-
9589
gulp.task('test-live-output-with-file', function () {
9690
var mocha = mochaStream({
9791
liveOutput: true,
@@ -139,6 +133,32 @@ gulp.task('test-live-output-with-prepend', function () {
139133
.pipe(mocha);
140134
});
141135

136+
gulp.task('test-mocha-opts-parallel', function () {
137+
function setEnv(envs) {
138+
var env = process.env;
139+
env = _.clone(env);
140+
env = _.merge(env, envs, {JUNIT_REPORT_PATH: path.resolve(__dirname, 'test/report/report.xml')});
141+
return env;
142+
}
143+
144+
var opts = {
145+
concurrency: 3,
146+
flags: {R: 'mocha-jenkins-reporter'},
147+
iterations: [{
148+
env: setEnv({NODE_ENV: 'groupa'}),
149+
flags: {grep: "@groupA@"}
150+
}, {
151+
env: setEnv({NODE_ENV: 'groupb'}),
152+
flags: {grep: "@groupB@"}
153+
}, {
154+
env: setEnv({NODE_ENV: 'groupc'}),
155+
flags: {grep: "@groupC@"}
156+
}]
157+
};
158+
var mocha = mochaStream(opts);
159+
gulp.src('test/group/*-specs.js')
160+
.pipe(mocha);
161+
});
142162

143163
gulp.task('test', function () {
144164
return runSequence(
@@ -147,6 +167,7 @@ gulp.task('test', function () {
147167
'test-live-output',
148168
'test-live-output-with-prepend',
149169
'test-live-output-with-file',
150-
'test-with-file'
170+
'test-with-file',
171+
'test-mocha-opts-parallel'
151172
);
152173
});

lib/index.js

Lines changed: 55 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22

33
// Module Requirements
44
var _ = require('lodash'),
5-
proc = require('child_process'),
6-
join = require('path').join,
7-
async = require('async'),
8-
util = require('util'),
9-
EventEmitter = require('events').EventEmitter,
10-
streamBuffers = require("stream-buffers"),
11-
through = require('through'),
12-
split = require('split'),
13-
fs = require('fs');
5+
proc = require('child_process'),
6+
join = require('path').join,
7+
async = require('async'),
8+
util = require('util'),
9+
EventEmitter = require('events').EventEmitter,
10+
streamBuffers = require("stream-buffers"),
11+
through = require('through'),
12+
split = require('split'),
13+
fs = require('fs');
1414

1515
require('colors');
1616

1717
function newStreamBuffer() {
1818
var stream = new streamBuffers.WritableStreamBuffer({
19-
initialSize: (25 * 1024),
20-
incrementAmount: (10 * 1024)
19+
initialSize: (25 * 1024),
20+
incrementAmount: (10 * 1024)
2121
});
2222
return stream;
2323
}
@@ -30,15 +30,20 @@ var SpawnMocha = function (opts) {
3030
});
3131
var queue = async.queue(function (task, done) {
3232
// Setup
33+
var _opts = opts;
34+
//merge iterationOpts, if any
35+
if (task.iterationOpts) {
36+
_opts = _.merge(opts, task.iterationOpts);
37+
}
3338
var bin = _.isFunction(opts.bin) ? opts.bin() : opts.bin ||
34-
join(__dirname, '..', 'node_modules', '.bin', 'mocha');
35-
var env = _.isFunction(opts.env) ? opts.env() : opts.env || process.env;
39+
join(__dirname, '..', 'node_modules', '.bin', 'mocha');
40+
var env = _.isFunction(_opts.env) ? _opts.env() : _opts.env || process.env;
3641
env = _.clone(env);
3742

3843
// Generate arguments
3944
var args = [];
40-
_(opts.flags).each(function (val, key) {
41-
if(_.isFunction(val)) val = val();
45+
_(_opts.flags).each(function (val, key) {
46+
if (_.isFunction(val)) val = val();
4247
args.push((key.length > 1 ? '--' : '-') + key);
4348
if (_.isString(val) || _.isNumber(val)) {
4449
args.push(val);
@@ -47,27 +52,26 @@ var SpawnMocha = function (opts) {
4752

4853
var stdout = newStreamBuffer();
4954
var stderr = newStreamBuffer();
50-
var fsStream = opts.fileOutput ?
51-
fs.createWriteStream(opts.fileOutput, { flags: 'a', encoding: 'utf8' }) : null;
55+
var fsStream = _opts.fileOutput ?
56+
fs.createWriteStream(_opts.fileOutput, {flags: 'a', encoding: 'utf8'}) : null;
5257

5358
// Split xunit test report in several files if required
54-
if(env.JUNIT_REPORT_PATH) {
55-
env.JUNIT_REPORT_PATH = env.JUNIT_REPORT_PATH + '.' + task.taskNum;
59+
if (env.JUNIT_REPORT_PATH) {
60+
env.JUNIT_REPORT_PATH = env.JUNIT_REPORT_PATH.replace(/xml$/, task.taskNum + '.xml');
5661
}
57-
console.log('haoooooo', task.files);
5862
// Execute Mocha
5963
var child = proc.spawn(bin, args.concat(task.files), {env: env});
6064

6165
if (opts.liveOutput) {
6266
child.stdout.pipe(split())
6367
.on('data', function (line) {
64-
console.log((opts.liveOutputPrepend || '') + line);
68+
console.log((_opts.liveOutputPrepend || '') + line);
6569
});
6670
child.stderr.pipe(split())
6771
.on('data', function (line) {
68-
console.error((opts.liveOutputPrepend || '') + line);
72+
console.error((_opts.liveOutputPrepend || '') + line);
6973
});
70-
if(fsStream) {
74+
if (fsStream) {
7175
child.stdout.pipe(fsStream);
7276
child.stderr.pipe(fsStream);
7377
}
@@ -77,25 +81,27 @@ var SpawnMocha = function (opts) {
7781
}
7882

7983
// When done...
80-
child.on('close', function(errCode) {
81-
if(stdout.size()) {
84+
child.on('close', function (errCode) {
85+
if (stdout.size()) {
8286
var contentOut = stdout.getContentsAsString("utf8");
8387
console.log(contentOut);
84-
if(fsStream) {
88+
if (fsStream) {
8589
fsStream.write(contentOut + '\n', 'utf8');
8690
}
8791
}
88-
if(stderr.size()) {
92+
if (stderr.size()) {
8993
var contentErr = stdout.getContentsAsString("utf8");
9094
console.error(contentErr);
91-
if(fsStream) {
95+
if (fsStream) {
9296
fsStream.write(contentErr + '\n', 'utf8');
9397
}
9498
}
95-
if(fsStream) { fsStream.close(); }
99+
if (fsStream) {
100+
fsStream.close();
101+
}
96102

97103
var err = null;
98-
if(errCode && opts.errorSummary) {
104+
if (errCode && opts.errorSummary) {
99105
err = new Error('Error for files: ' + task.files.join(', '));
100106
err.files = task.files;
101107
err.stderr = stderr.size() ? stderr.getContentsAsString("utf8") : '';
@@ -105,19 +111,19 @@ var SpawnMocha = function (opts) {
105111
});
106112
}, opts.concurrency || 1);
107113

108-
queue.drain = function() {
114+
queue.drain = function () {
109115
_this.emit('end');
110116
};
111117

112118
var taskNum = 0;
113-
this.add = function(files) {
114-
taskNum ++;
119+
this.add = function (files, iterationOpts) {
120+
taskNum++;
115121
if (!_.isArray(files)) {
116122
files = [files];
117123
}
118-
var task = {taskNum: taskNum, files: files};
119-
queue.push(task, function(err) {
120-
if(err){
124+
var task = {taskNum: taskNum, files: files, iterationOpts: iterationOpts || {}};
125+
queue.push(task, function (err) {
126+
if (err) {
121127
_this.emit('error', err, files);
122128
}
123129
});
@@ -128,46 +134,25 @@ util.inherits(SpawnMocha, EventEmitter);
128134

129135
var mochaStream = function mocha(opts) {
130136
opts = opts || {};
131-
var spawnMocha = new SpawnMocha(opts);
132-
var stream = through(function write(file) {
133-
spawnMocha.add(file.path);
134-
}, function() {});
135-
var errors = [];
136-
spawnMocha.on('error', function(err) {
137-
console.error(err.toString());
138-
errors.push(err);
139-
}).on('end', function() {
140-
if(errors.length > 0) {
141-
console.error('ERROR SUMMARY: ');
142-
_(errors).each(function(err) {
143-
console.error(err);
144-
console.error(err.stack);
145-
}).value();
146-
stream.emit('error', "Some tests failed.");
147-
}
148-
stream.emit('end');
149-
});
150-
return stream;
151-
};
152-
153-
var mochaOptsStream = function mocha(opts) {
154137
var files = [];
155-
opts = opts || {};
156138
var spawnMocha = new SpawnMocha(opts);
157139
var stream = through(function write(file) {
158-
//spawnMocha.add(file.path);
159-
files.push(file.path);
160-
}, function() {
161-
spawnMocha.add(files);
140+
(opts.iterations) ? files.push(file.path) : spawnMocha.add(file.path);
141+
}, function () {
142+
if (opts.iterations) {
143+
opts.iterations.forEach(function (iteration) {
144+
spawnMocha.add(files, iteration);
145+
});
146+
}
162147
});
163148
var errors = [];
164-
spawnMocha.on('error', function(err) {
149+
spawnMocha.on('error', function (err) {
165150
console.error(err.toString());
166151
errors.push(err);
167-
}).on('end', function() {
168-
if(errors.length > 0) {
152+
}).on('end', function () {
153+
if (errors.length > 0) {
169154
console.error('ERROR SUMMARY: ');
170-
_(errors).each(function(err) {
155+
_(errors).each(function (err) {
171156
console.error(err);
172157
console.error(err.stack);
173158
}).value();
@@ -177,8 +162,8 @@ var mochaOptsStream = function mocha(opts) {
177162
});
178163
return stream;
179164
};
165+
180166
module.exports = {
181167
SpawnMocha: SpawnMocha,
182-
mochaStream: mochaStream,
183-
mochaOptsStream: mochaOptsStream
168+
mochaStream: mochaStream
184169
};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"fixture-stdout": "^0.2.1",
4040
"from": "^0.1.3",
4141
"gulp": "^3.8.8",
42+
"mocha-jenkins-reporter": "^0.1.8",
4243
"q": "^1.1.2",
4344
"run-sequence": "^1.0.1",
4445
"vinyl": "^0.4.3"

test/b-test-specs.js

Lines changed: 0 additions & 11 deletions
This file was deleted.

test/c-test-specs.js

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)