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'],
22 .option('test-fast', {
23 describe: 'only run fast tests',
27 .option('test-parallel', {
28 describe: 'run tests in parallel',
32 .option('test-coverage', {
33 describe: 'generate coverage on tests',
37 .option('test-bail', {
38 describe: 'bail on first failure',
42 .option('test-xunit-reports', {
43 describe: 'generate xunit reports',
47 .option('test-grep', {
49 describe: 'grep tests',
52 .option('test-critical-only', {
53 describe: 'only test critical tests',
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);
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')],
84 testModules['request-tests'] = {
86 './test/request-api-tests/'
87 // XXX: Skipped because Gitter login is now disabled (#gitter-sunset)
88 //'./test/request-web-tests/'
91 // These tests load the entire app, so mocha will sometimes timeout before it even runs the tests
97 testModules.integration = {
98 files: ['./test/integration/'],
102 // eslint-disable-next-line max-statements, complexity
103 function spawnMochaProcess(moduleName, options, files) {
107 var argReporter = 'spec';
108 var argTimeout = (options && options.timeout) || 10000;
112 SKIP_BADGER_TESTS: 1,
119 if (generateCoverage) {
120 executable = './node_modules/.bin/nyc';
124 'output/coverage-reports/' + moduleName,
127 './node_modules/.bin/mocha'
130 mkdirp.sync('output/coverage-reports/' + moduleName);
132 executable = './node_modules/.bin/mocha';
136 // This is needed because Mocha no longer force exits, https://boneskull.com/mocha-v4-nears-release/#mochawontforceexit
139 if (testSuite === 'docker') {
140 env.HOME = '/tmp'; // Needs to be writeable inside docker for `nyc`
141 env.NODE_ENV = 'test-docker';
145 var argInvert = false;
150 } else if (disableGitHubTests) {
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');
166 args.push(argReporter);
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);
191 var testingErrors = [];
193 Object.keys(testModules).forEach(function(moduleName) {
194 var definition = testModules[moduleName];
196 if (criticalOnly && !definition.isCritical) {
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) {
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() {
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]);
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]);
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() {
264 .src('output/coverage-reports/**/lcov.info')
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';
274 .src('output/coverage-reports/merged/lcov.info')
280 .on('error', function(err) {
287 * Hook into the clean stage
289 gulp.task('test:clean', function(cb) {
290 del(['.nyc_output/'], cb);