gulpphpunitrun-sequence

Gulp postpone error occurring whilst running run-sequence to end of tasks list


I have a Gulpfile for a Laravel application. The unit tests for the application are executed via Gulp. To execute the tests correctly the following tasks should run in a synchronous order (via run-sequence).

This works fine, however, there is a problem when PHPUnit executes and one or more unit tests have failed. If this happens the sequence is broken and as a result switching back to the original environment doesn't happen and we're stuck at the testing environment.

That's why I would like to postpone the PHPUnit error to the end of the sequence. This way the environment gets restored but, for CI purposes, the build will still be marked as failed.

I've tried something myself with gulp-if and gulp-fail. The gulp-fail code is executed but the run-sequence keeps executing anyway. I don't know how to fix this.

Here's what I tried to catch the unit tests failure:

.on('error', function() {
       didTestsFail = true;
       this.emit('end');
   })

and with this task I'm trying to mark the build as failed:

gulp.task('error-when-tests-failed', function() {
    return gulp.src('./')
        .pipe(gulpIf(didTestsFail, fail()));
});

So basically, I'm using a global var to determine whether the unit tests have failed or not.

Here's the complete Gulpfile:

var gulp = require('gulp'),
    del = require('del'),
    rename = require('gulp-rename'),
    exec = require('gulp-exec'),
    foreach = require('gulp-foreach'),
    gulpSequence = require('gulp-sequence').use(gulp),
    plumber = require('gulp-plumber'),
    phpunit = require('gulp-phpunit'),
    fail   = require('gulp-fail'),
    gulpIf = require('gulp-if'),
    db = require('gulp-db')({
        user: 'user',
        password: 'some_password',
        host: 'some_host',
        port: 'some_port',
        dialect: 'mysql'
    }),

    didTestsFail = false;

gulp.task('tests', function(cb) {
    gulpSequence(
        'back-up-active-env',
        'switch-testing-env',
        'create-test-database',
        'migrate',
        'phpunit',
        'drop-test-database',
        'restore-active-env',
        'error-when-tests-failed'
    )(cb);
});

gulp.task('phpunit', function(done) {
    var options = {
        debug: false,
        statusLine: true
    };

    return gulp.src('phpunit.xml')
               .pipe(plumber())
               .pipe(phpunit('./vendor/bin/phpunit', options))
               .on('error', function() {
                   didTestsFail = true;
                   this.emit('end');
               });
});

gulp.task('back-up-active-env', function() {
    del('env.temp');
    return gulp.src('.env')
        .pipe(plumber())
        .pipe(rename('.env.temp'))
        .pipe(gulp.dest('./'));
});

gulp.task('migrate', function() {
    return gulp.src('./')
        .pipe(plumber())
        .pipe(exec('php artisan migrate'));
});

gulp.task('switch-testing-env', function() {
    del('.env');
    return gulp.src('.env.testing')
        .pipe(plumber())
        .pipe(rename('.env'))
        .pipe(gulp.dest('./'))
        .pipe(exec('php artisan config:cache'));
});

gulp.task('restore-active-env', function() {
    del('.env');
    return gulp.src('.env.temp')
        .pipe(plumber())
        .pipe(rename('.env'))
        .pipe(gulp.dest('./'))
        .pipe(exec('php artisan config:cache'));
});

gulp.task('error-when-tests-failed', function() {
    return gulp.src('./')
        .pipe(gulpIf(didTestsFail, fail()));
});

gulp.task('create-test-database', db.create('test_db'));;
gulp.task('drop-test-database', db.drop('test_db'));

Solution

  • After some fiddling around I figured out how I can make it work:

    There is no need for the error-when-tests-failed task, it was kind of hacky anyway.

    You can pass a callback to the gulpSequence function, in this callback you can check if the didTestsFail var is true, if so you can throw an error. The code looks as follows:

    gulp.task('tests', function(done) {
        gulpSequence(
            'back-up-active-env',
            'switch-testing-env',
            'create-old-test-database',
            'create-new-test-database',
            'migrate',
            'phpunit',
            'drop-old-test-database',
            'drop-new-test-database',
            'restore-active-env',
            function() {
                if (didTestsFail) {
                    throw new Error('One or more unit tests failed!');
                }
                done();
            }
        );
    });