4

I'm trying to integrate Gulp with Tape (https://github.com/substack/tape), the NodeJs test harness.

How can I do this? There doesn't seem to be an existing gulp plugin.

I've see this, but it looks really inelegant:

var shell = require('gulp-shell')

gulp.task('exec-tests', shell.task([
  'tape test/* | faucet',
]));

gulp.task('autotest', ['exec-tests'], function() {
  gulp.watch(['app/**/*.js', 'test/**/*.js'], ['exec-tests']);
});

I've tried this, which looks like it should work:

var tape = require('tape');
var spec = require('tap-spec');


gulp.task('test', function() {
    return gulp.src(paths.serverTests, {
            read: false
        })
        .pipe(tape.createStream())
        .pipe(spec())
        .pipe(process.stdout);
});

but I get a TypeError: Invalid non-string/buffer chunk error

gotofritz
  • 3,341
  • 1
  • 31
  • 47
Joseph
  • 914
  • 2
  • 14
  • 29

6 Answers6

4

Your "inelegant" answer is the best one. Not every problem can be best solved with streams, and using gulp just as a wrapper is not a sin.

gotofritz
  • 3,341
  • 1
  • 31
  • 47
  • I confirm. I've tried many others "solutions" and this is the only one which works well inside a watch. All others like gulp-tape or using xargs works only once and then crash on the second run triggered by the watch. – MathieuLescure Oct 06 '15 at 15:14
2

Right, your task won't work because gulp streams are based on vinyl, a virtual file abstraction. I don't really think there's a good way of handling this in gulp, it seems like you should be using the tape API directly. I mean, you could put some gulp task sugar around it if you wish:

var test = require('tape');
var spec = require('tap-spec');
var path = require('path');
var gulp = require('gulp');
var glob = require('glob');

gulp.task('default', function () {
    var stream = test.createStream()
        .pipe(spec())
        .pipe(process.stdout);

    glob.sync('path/to/tests/**/*.js').forEach(function (file) {
        require(path.resolve(file));
    });

    return stream;
});

Seems kind of messy to me; not only because we're not using any of gulp's streaming abstractions, but we're not even putting it into a way that could hook into a gulp pipeline afterwards. Furthermore, you can't get gulp's task finished message when using this code either. If anyone knows a way around that then, please, be my guest. :-)

I think I would prefer to use tape on the command line. But, if you want all of your build step tasks in your gulpfile this might be the route to go.

Ben
  • 10,106
  • 3
  • 40
  • 58
1

Just use code below and gulp tdd and having TDD :) with tape

const tapNotify = require('tap-notify');
const colorize = require('tap-colorize');
const tape = require('gulp-tape');
const through = require('through2');
gulp.task('test',function(){
    process.stdout.write('\x1Bc');
    const reporter = through.obj();
    reporter.pipe(tapNotify({
        passed: {title: 'ok', wait:false},
        failed: {title: 'missing',wait:false}
    }));
    reporter
        .pipe(colorize())
        .pipe(process.stdout);
    return gulp.src('test/**/*.js')
        .pipe(tape({
            outputStream: through.obj(),
            reporter: reporter
        }));
});
gulp.task('tdd', function() {
    gulp.run('test');
    gulp.watch(['app/scripts/**/*.js*', 'test/**/*.js'],['test']);
});
o0omycomputero0o
  • 3,316
  • 4
  • 31
  • 45
0

In a GitHub issue for tape jokeyrhyme mentions that gulp tasks can be Promises, and suggests a way to use that for running tape tests. Based upon that advice I've done this:

gulpfile.babel.js:

import glob from "glob";

gulp.task("test", () => {
    let module = process.argv[process.argv.length - 1];

    return new Promise(resolve => {
        // Crude test for 'gulp test' vs. 'gulp test --module mod'
        if (module !== "test") {
            require(`./js/tape/${module}.js`);
            resolve();
            return;
        }

        glob.sync("./js/tape/*.js").forEach(f => require(f)));
        resolve();
    });
});

Looking at Ben's answer I suspect what I've done isn't very nice though, for one thing I've noticed that failing tests don't result in a non-zero exit code (although I've not tried Ben's approach to validate whether that does).

Community
  • 1
  • 1
Richard Turner
  • 12,506
  • 6
  • 36
  • 37
0
// npm i --save-dev gulp-tape
// npm i --save-dev faucet (just an example of using a TAP reporter)

import gulp from 'gulp';
import tape from 'gulp-tape'; 
import faucet from 'faucet';

gulp.task('test:js', () => {
    return gulp.src('src/**/*test.js')
        .pipe(tape({
            reporter: faucet()
        }));
});
leon
  • 762
  • 1
  • 10
  • 24
0

Here's an example of my solution:

var gulp = require('gulp');
var tape = require('tape');
var File = require('vinyl');
var through = require('through2');
var exec = (require('child_process')).execSync;

function execShell(shcmd, opts) {
    var out = '';
    try {
        out = exec(shcmd, opts);
    } catch (e) {
        if (e.error) throw e.error;
        if (e.stdout) out = e.stdout.toString();
    }
    return out;
};

gulp.task('testreport', function(){
    return gulp.src(
        'testing/specs/tape_unit.js', {read: false}
    ).pipe(
        through.obj(function(file, encoding, next) {
            try{
                // get tape's report
                var tapout = execShell(
                    "./node_modules/.bin/tape " + file.path
                );
                // show the report in a console with tap-spec
                execShell(
                    "./node_modules/.bin/tap-spec", { input: tapout, stdio: [null, 1, 2] }
                );
                // make a json report
                var jsonout = execShell(
                    "./node_modules/.bin/tap-json", { input: tapout }
                );
                // do something with report's object
                // or prepare it for something like Bamboo
                var report = JSON.parse(jsonout.toString());
                // continue the stream with the json report
                next(null, new File({
                    path: 'spec_report.json',
                    contents: new Buffer(JSON.stringify(report, null, 2))
                }));
            }catch(err){ next(err) }
        })
    ).pipe(
        gulp.dest('testing/reports')
    );
});
Denis S Kryukov
  • 508
  • 5
  • 10