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'] = {
85 files: ['./test/request-api-tests/', './test/request-web-tests/'],
87 // These tests load the entire app, so mocha will sometimes timeout before it even runs the tests
93 testModules.integration = {
94 files: ['./test/integration/'],
98 // eslint-disable-next-line max-statements, complexity
99 function spawnMochaProcess(moduleName, options, files) {
103 var argReporter = 'spec';
104 var argTimeout = (options && options.timeout) || 10000;
108 SKIP_BADGER_TESTS: 1,
115 if (generateCoverage) {
116 executable = './node_modules/.bin/nyc';
120 'output/coverage-reports/' + moduleName,
123 './node_modules/.bin/mocha'
126 mkdirp.sync('output/coverage-reports/' + moduleName);
128 executable = './node_modules/.bin/mocha';
132 // This is needed because Mocha no longer force exits, https://boneskull.com/mocha-v4-nears-release/#mochawontforceexit
135 if (testSuite === 'docker') {
136 env.HOME = '/tmp'; // Needs to be writeable inside docker for `nyc`
137 env.NODE_ENV = 'test-docker';
141 var argInvert = false;
146 } else if (disableGitHubTests) {
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');
159 args.push('--recursive');
162 args.push(argReporter);
174 args.push('--invert');
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);
187 var testingErrors = [];
189 Object.keys(testModules).forEach(function(moduleName) {
190 var definition = testModules[moduleName];
192 if (criticalOnly && !definition.isCritical) {
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) {
202 throw new Error('Test module ' + moduleName + ' failed. ' + err);
205 testingErrors.push(err);
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() {
218 if (testSuite === 'docker') {
219 env.NODE_ENV = 'test-docker';
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]);
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]);
247 runSequence.apply(null, args);
252 * Hook into post test
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() {
260 .src('output/coverage-reports/**/lcov.info')
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';
270 .src('output/coverage-reports/merged/lcov.info')
276 .on('error', function(err) {
283 * Hook into the clean stage
285 gulp.task('test:clean', function(cb) {
286 del(['.nyc_output/'], cb);