Gitter migration: Setup redirects (rollout pt. 3)
[gitter.git] / build-scripts / gulpfile-test.js
blob2ef91f7344dba5e49bb0740fdb57b9a1e3459a09
1 'use strict';
3 var gulp = require('gulp');
4 var gutil = require('gulp-util');
5 var runSequence = require('run-sequence');
6 var using = require('gulp-using');
7 var codecov = require('gulp-codecov');
8 var lcovMerger = require('lcov-result-merger');
9 var path = require('path');
10 var mkdirp = require('mkdirp');
11 var glob = require('glob');
12 var childProcessPromise = require('./child-process-promise');
13 var del = require('del');
14 var Promise = require('bluebird');
16 var argv = require('yargs')
17 .option('test-suite', {
18 describe: 'test-suite to run',
19 choices: ['local', 'mocha', 'docker'],
20 default: 'local'
22 .option('test-fast', {
23 describe: 'only run fast tests',
24 boolean: true,
25 default: false
27 .option('test-parallel', {
28 describe: 'run tests in parallel',
29 boolean: true,
30 default: false
32 .option('test-coverage', {
33 describe: 'generate coverage on tests',
34 boolean: true,
35 default: false
37 .option('test-bail', {
38 describe: 'bail on first failure',
39 boolean: true,
40 default: false
42 .option('test-xunit-reports', {
43 describe: 'generate xunit reports',
44 boolean: true,
45 default: false
47 .option('test-grep', {
48 alias: 'g',
49 describe: 'grep tests',
50 type: 'string'
52 .option('test-critical-only', {
53 describe: 'only test critical tests',
54 boolean: true,
55 default: false
57 .help('test-help').argv;
59 /* Don't do clean in gulp, use make */
60 var RUN_TESTS_IN_PARALLEL = argv['test-parallel'];
61 var generateCoverage = argv['test-coverage'];
62 var generateXUnitReports = argv['test-xunit-reports'];
63 var bail = argv['test-bail'];
64 var testSuite = argv['test-suite'];
65 var fast = argv['test-fast'];
66 var grep = argv['test-grep'];
67 var criticalOnly = argv['test-critical-only'];
68 const disableGitHubTests =
69 process.env.DISABLE_GITHUB_TESTS && JSON.parse(process.env.DISABLE_GITHUB_TESTS);
71 var testModules = {};
73 var modulesWithTest = glob.sync('./modules/*/test');
75 modulesWithTest.forEach(function(testDir) {
76 var moduleDir = path.dirname(testDir);
77 var moduleName = path.basename(moduleDir);
78 testModules[moduleName] = {
79 files: [path.join('modules', moduleName, 'test')],
80 isCritical: false
82 });
84 testModules['request-tests'] = {
85 files: [
86 './test/request-api-tests/'
87 // XXX: Skipped because Gitter login is now disabled (#gitter-sunset)
88 //'./test/request-web-tests/'
90 options: {
91 // These tests load the entire app, so mocha will sometimes timeout before it even runs the tests
92 timeout: 30000
94 isCritical: false
97 testModules.integration = {
98 files: ['./test/integration/'],
99 isCritical: true
102 // eslint-disable-next-line max-statements, complexity
103 function spawnMochaProcess(moduleName, options, files) {
104 var executable;
105 var args;
107 var argReporter = 'spec';
108 var argTimeout = (options && options.timeout) || 10000;
109 var argBail = bail;
111 var env = {
112 SKIP_BADGER_TESTS: 1,
113 BLUEBIRD_DEBUG: 1,
114 NO_AUTO_INDEX: 1,
115 TZ: 'UTC',
116 GITTER_TEST: 1
119 if (generateCoverage) {
120 executable = './node_modules/.bin/nyc';
121 args = [
122 '--cache',
123 '--report-dir',
124 'output/coverage-reports/' + moduleName,
125 '--reporter',
126 'lcov',
127 './node_modules/.bin/mocha'
130 mkdirp.sync('output/coverage-reports/' + moduleName);
131 } else {
132 executable = './node_modules/.bin/mocha';
133 args = [];
136 // This is needed because Mocha no longer force exits, https://boneskull.com/mocha-v4-nears-release/#mochawontforceexit
137 args.push('--exit');
139 if (testSuite === 'docker') {
140 env.HOME = '/tmp'; // Needs to be writeable inside docker for `nyc`
141 env.NODE_ENV = 'test-docker';
144 var argGrep = grep;
145 var argInvert = false;
146 if (fast) {
147 argGrep = '#slow';
148 argInvert = true;
149 argBail = true;
150 } else if (disableGitHubTests) {
151 argGrep = '#github';
152 argInvert = true;
155 if (generateXUnitReports) {
156 mkdirp.sync('output/test-reports/');
158 argReporter = 'mocha-multi';
159 env.multi = 'spec=- xunit=output/test-reports/' + moduleName + '.xml';
160 gutil.log('Will write xunit reports to', 'output/test-reports/' + moduleName + '.xml');
163 args.push('--recursive');
165 args.push('-R');
166 args.push(argReporter);
168 if (argGrep) {
169 args.push('--grep');
170 args.push(argGrep);
173 if (argBail) {
174 args.push('--bail');
177 if (argInvert) {
178 args.push('--invert');
181 args.push('--timeout');
182 args.push(argTimeout);
184 args = args.concat(files);
185 gutil.log('Running tests with', executable, args.join(' '));
187 return childProcessPromise.spawn(executable, args, env);
190 var subTasks = [];
191 var testingErrors = [];
193 Object.keys(testModules).forEach(function(moduleName) {
194 var definition = testModules[moduleName];
196 if (criticalOnly && !definition.isCritical) {
197 return;
200 var testTaskName = 'test:test:' + moduleName;
201 subTasks.push(testTaskName);
203 gulp.task(testTaskName, function() {
204 return spawnMochaProcess(moduleName, definition.options, definition.files).catch(function(err) {
205 if (bail) {
206 throw new Error('Test module ' + moduleName + ' failed. ' + err);
209 testingErrors.push(err);
214 subTasks.push('test:test:jest');
215 gulp.task('test:test:jest', function() {
216 return childProcessPromise.spawn('npm', ['run', 'jest']);
219 gulp.task('test:pre-test', function() {
220 var env = {};
222 if (testSuite === 'docker') {
223 env.NODE_ENV = 'test-docker';
226 return childProcessPromise.spawn('./scripts/utils/ensure-mongodb-indexes.js', [], env);
229 if (RUN_TESTS_IN_PARALLEL) {
230 // Run tests in parallel
231 gulp.task('test:test', subTasks, function() {
232 if (testingErrors.length) {
233 return Promise.reject(testingErrors[0]);
236 } else {
237 // Run tests in sequence
238 gulp.task('test:test', function(callback) {
239 gutil.log('Run sequence for test:test', subTasks.join(','));
241 var args = subTasks.concat(function(err) {
242 if (err) return callback(err);
244 if (testingErrors.length) {
245 return callback(testingErrors[0]);
248 return callback();
251 runSequence.apply(null, args);
256 * Hook into post test
258 if (generateCoverage) {
259 gulp.task('test:post-test', ['test:post-test:merge-lcov', 'test:post-test:submit-codecov']);
262 gulp.task('test:post-test:merge-lcov', function() {
263 return gulp
264 .src('output/coverage-reports/**/lcov.info')
265 .pipe(using())
266 .pipe(lcovMerger())
267 .pipe(gulp.dest('output/coverage-reports/merged/'));
270 gulp.task('test:post-test:submit-codecov', ['test:post-test:merge-lcov'], function() {
271 process.env.CODECOV_TOKEN = '4d30a5c7-3839-4396-a2fd-d8f9a68a5c3a';
273 return gulp
274 .src('output/coverage-reports/merged/lcov.info')
275 .pipe(
276 codecov({
277 disable: 'gcov'
280 .on('error', function(err) {
281 gutil.log(err);
282 this.emit('end');
287 * Hook into the clean stage
289 gulp.task('test:clean', function(cb) {
290 del(['.nyc_output/'], cb);