Gulp: How to execute a gulp plugin programatically (integration testing)

Created on 27 May 2014  路  6Comments  路  Source: gulpjs/gulp

I have a simple function that does 3 things and then I return that fn and register a name w/ gulp so I can invoke it later.

module.exports = function(gulp, options) {
    var concat = require('gulp-concat');
    var react = require('gulp-react');

    gulp.task('foo', [], function(){
        return gulp.src("/**/*.jsx")
            .pipe(react())
            .pipe(concat('react.js'))
            .pipe(gulp.dest('./build'));
    });
};

On the surface this appears to return something that's streaming because when I print it from a test I get the usual writable/readable/end/destroy/pause/resume

I'm trying to test this by doing the following

describe("react task integration tests", function() {
    it("should transform jsx to vanilla javascript", function(done) {
        //this require will pull in the above module
        var react = require('../tasks/react')(gulp, options);
        var outstream = gulp.tasks.foo.fn();
        outstream.on('end', function() {
            //here I expect to see the content written but .. sadly no
            done();
        });
    });
});

But when I get into the stream.end I see the file is not written like I expect. If I do the following it does work. (notice I'm doing the entire thing by hand, and I'd much prefer to invoke the function you see above that does all the src/pipe/concat/react/dest work

describe("react task integration tests", function() {
    it("should transform jsx to vanilla javascript", function(done) {
            var react = require('gulp-react');
            var concat = require('gulp-concat');
            var instream = gulp.src(join(__dirname, "./src/react.jsx"));
            var outstream = instream.pipe(react());
            var outstream2 = outstream.pipe(concat('react.js'));
            var outstream3 = outstream2.pipe(gulp.dest('./test/tasks/build'));
            outstream3.on('end', function() {
                        //at this point when I read from the filesystem I have the output
                        done();
                    });
        });
});

Is it possible to test gulp functions that batch up a few operations into a single streamable like this? What am I doing wrong? Thanks for the help!

Most helpful comment

I still plan to blog about this topic but for now the TL;DR

Say you wanted to test the react task using gulp. The trick is to register an example (fake) task that requires the task you want to get under test. Then using an async test framework like mocha or jasmine you kick off the fake / example task using grunt.start and throw the done() inside the example so you can assert any given output.

describe("react gulp tests", function() {
        it("react transforms any jsx to vanilla javascript", function(done) {
            var react = require('gulp-react');
            var concat = require('gulp-concat');
            gulp.task('foo', function(){
                return gulp.src(join(__dirname, "**/*.jsx"))
                    .pipe(react())
                    .pipe(concat('react.js'))
                    .pipe(gulp.dest('dist'));
            });
            gulp.task('example', ['foo'], function() {
                //now get your expected output and compare it ....
                //expect(resultingFile).to.equal(expectedFile);
                done();
            });
            gulp.start(['example']);
        });
    });

All 6 comments

The contnet is written to disk by gulp.dest. You can get the contents in memory by listening to the data event and buffer it up until the end event or use something like concat-stream to do it for you.

Interestingly enough when I listen on data and do the close inside that callback (not doing the end at all) - I just timeout. Does this mean the on.data does not work as the stream would expect or is end something I must call to get this working?

One last question related this this (and a change that happened in gulp 3.5)

If i wanted to run a task manually before 3.5 I "could" do something like this

        gulp.run(['example']);

But if I run this today I get the deprecation warning below ...

gulp.run() has been deprecated. Use task dependencies or gulp.watch task triggering instead.

How should I "run" the example task from above using the latest gulp master?

**I assume when run is killed I won't be able to do this either?

        gulp.start.apply(gulp, ['example']);

@toranb

gulp.start('example');

I still plan to blog about this topic but for now the TL;DR

Say you wanted to test the react task using gulp. The trick is to register an example (fake) task that requires the task you want to get under test. Then using an async test framework like mocha or jasmine you kick off the fake / example task using grunt.start and throw the done() inside the example so you can assert any given output.

describe("react gulp tests", function() {
        it("react transforms any jsx to vanilla javascript", function(done) {
            var react = require('gulp-react');
            var concat = require('gulp-concat');
            gulp.task('foo', function(){
                return gulp.src(join(__dirname, "**/*.jsx"))
                    .pipe(react())
                    .pipe(concat('react.js'))
                    .pipe(gulp.dest('dist'));
            });
            gulp.task('example', ['foo'], function() {
                //now get your expected output and compare it ....
                //expect(resultingFile).to.equal(expectedFile);
                done();
            });
            gulp.start(['example']);
        });
    });

@toranb : small correction for script.

In task declaration:

gulp.task('example', ['foo'], function()

its better to add parameter "done" (or it will be undefined):

gulp.task('example', ['foo'], function(done)

Was this page helpful?
0 / 5 - 0 ratings