Merge tag '21.54.0' into develop
[gitter.git] / build-scripts / gulpfile-test.js
blob963ca827e2a334ab7ccc9bad468bb47653cc971b
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'
21   })
22   .option('test-fast', {
23     describe: 'only run fast tests',
24     boolean: true,
25     default: false
26   })
27   .option('test-parallel', {
28     describe: 'run tests in parallel',
29     boolean: true,
30     default: false
31   })
32   .option('test-coverage', {
33     describe: 'generate coverage on tests',
34     boolean: true,
35     default: false
36   })
37   .option('test-bail', {
38     describe: 'bail on first failure',
39     boolean: true,
40     default: false
41   })
42   .option('test-xunit-reports', {
43     describe: 'generate xunit reports',
44     boolean: true,
45     default: false
46   })
47   .option('test-grep', {
48     alias: 'g',
49     describe: 'grep tests',
50     type: 'string'
51   })
52   .option('test-critical-only', {
53     describe: 'only test critical tests',
54     boolean: true,
55     default: false
56   })
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
81   };
82 });
84 testModules['request-tests'] = {
85   files: ['./test/request-api-tests/', './test/request-web-tests/'],
86   options: {
87     // These tests load the entire app, so mocha will sometimes timeout before it even runs the tests
88     timeout: 30000
89   },
90   isCritical: false
93 testModules.integration = {
94   files: ['./test/integration/'],
95   isCritical: true
98 // eslint-disable-next-line max-statements, complexity
99 function spawnMochaProcess(moduleName, options, files) {
100   var executable;
101   var args;
103   var argReporter = 'spec';
104   var argTimeout = (options && options.timeout) || 10000;
105   var argBail = bail;
107   var env = {
108     SKIP_BADGER_TESTS: 1,
109     BLUEBIRD_DEBUG: 1,
110     NO_AUTO_INDEX: 1,
111     TZ: 'UTC',
112     GITTER_TEST: 1
113   };
115   if (generateCoverage) {
116     executable = './node_modules/.bin/nyc';
117     args = [
118       '--cache',
119       '--report-dir',
120       'output/coverage-reports/' + moduleName,
121       '--reporter',
122       'lcov',
123       './node_modules/.bin/mocha'
124     ];
126     mkdirp.sync('output/coverage-reports/' + moduleName);
127   } else {
128     executable = './node_modules/.bin/mocha';
129     args = [];
130   }
132   // This is needed because Mocha no longer force exits, https://boneskull.com/mocha-v4-nears-release/#mochawontforceexit
133   args.push('--exit');
135   if (testSuite === 'docker') {
136     env.HOME = '/tmp'; // Needs to be writeable inside docker for `nyc`
137     env.NODE_ENV = 'test-docker';
138   }
140   var argGrep = grep;
141   var argInvert = false;
142   if (fast) {
143     argGrep = '#slow';
144     argInvert = true;
145     argBail = true;
146   } else if (disableGitHubTests) {
147     argGrep = '#github';
148     argInvert = true;
149   }
151   if (generateXUnitReports) {
152     mkdirp.sync('output/test-reports/');
154     argReporter = 'mocha-multi';
155     env.multi = 'spec=- xunit=output/test-reports/' + moduleName + '.xml';
156     gutil.log('Will write xunit reports to', 'output/test-reports/' + moduleName + '.xml');
157   }
159   args.push('--recursive');
161   args.push('-R');
162   args.push(argReporter);
164   if (argGrep) {
165     args.push('--grep');
166     args.push(argGrep);
167   }
169   if (argBail) {
170     args.push('--bail');
171   }
173   if (argInvert) {
174     args.push('--invert');
175   }
177   args.push('--timeout');
178   args.push(argTimeout);
180   args = args.concat(files);
181   gutil.log('Running tests with', executable, args.join(' '));
183   return childProcessPromise.spawn(executable, args, env);
186 var subTasks = [];
187 var testingErrors = [];
189 Object.keys(testModules).forEach(function(moduleName) {
190   var definition = testModules[moduleName];
192   if (criticalOnly && !definition.isCritical) {
193     return;
194   }
196   var testTaskName = 'test:test:' + moduleName;
197   subTasks.push(testTaskName);
199   gulp.task(testTaskName, function() {
200     return spawnMochaProcess(moduleName, definition.options, definition.files).catch(function(err) {
201       if (bail) {
202         throw new Error('Test module ' + moduleName + ' failed. ' + err);
203       }
205       testingErrors.push(err);
206     });
207   });
210 subTasks.push('test:test:jest');
211 gulp.task('test:test:jest', function() {
212   return childProcessPromise.spawn('npm', ['run', 'jest']);
215 gulp.task('test:pre-test', function() {
216   var env = {};
218   if (testSuite === 'docker') {
219     env.NODE_ENV = 'test-docker';
220   }
222   return childProcessPromise.spawn('./scripts/utils/ensure-mongodb-indexes.js', [], env);
225 if (RUN_TESTS_IN_PARALLEL) {
226   // Run tests in parallel
227   gulp.task('test:test', subTasks, function() {
228     if (testingErrors.length) {
229       return Promise.reject(testingErrors[0]);
230     }
231   });
232 } else {
233   // Run tests in sequence
234   gulp.task('test:test', function(callback) {
235     gutil.log('Run sequence for test:test', subTasks.join(','));
237     var args = subTasks.concat(function(err) {
238       if (err) return callback(err);
240       if (testingErrors.length) {
241         return callback(testingErrors[0]);
242       }
244       return callback();
245     });
247     runSequence.apply(null, args);
248   });
252  * Hook into post test
253  */
254 if (generateCoverage) {
255   gulp.task('test:post-test', ['test:post-test:merge-lcov', 'test:post-test:submit-codecov']);
258 gulp.task('test:post-test:merge-lcov', function() {
259   return gulp
260     .src('output/coverage-reports/**/lcov.info')
261     .pipe(using())
262     .pipe(lcovMerger())
263     .pipe(gulp.dest('output/coverage-reports/merged/'));
266 gulp.task('test:post-test:submit-codecov', ['test:post-test:merge-lcov'], function() {
267   process.env.CODECOV_TOKEN = '4d30a5c7-3839-4396-a2fd-d8f9a68a5c3a';
269   return gulp
270     .src('output/coverage-reports/merged/lcov.info')
271     .pipe(
272       codecov({
273         disable: 'gcov'
274       })
275     )
276     .on('error', function(err) {
277       gutil.log(err);
278       this.emit('end');
279     });
283  * Hook into the clean stage
284  */
285 gulp.task('test:clean', function(cb) {
286   del(['.nyc_output/'], cb);