"Писать после завершения": как имитировать глоток с watchify?

Следующая задача Gulp делает почти то, что я хочу.

const gulp = require('gulp');
const browserify = require('browserify');
const vinylStream = require('vinyl-source-stream');
const vinylBuffer = require('vinyl-buffer');
const watchify = require('watchify');
const glob = require('glob');
const jasmineBrowser = require('gulp-jasmine-browser');

gulp.task('test', function() {
    let testBundler = browserify({
        entries: glob.sync('src/**/*-test.js'),
        cache: {},
        packageCache: {},
    }).plugin(watchify);
    function updateSpecs() {
        return testBundler.bundle()
            .pipe(vinylStream(jsBundleName))
            .pipe(vinylBuffer())
            .pipe(jasmineBrowser.specRunner({console: true}))
            .pipe(jasmineBrowser.headless({driver: 'phantomjs'}));
    }
    testBundler.on('update', updateSpecs);
    updateSpecs();
});

Он связывает все мои спецификации Jasmine с использованием Browserify и тестирует их через gulp-jasmine-browser. Он также просматривает все спецификации и все модули, от которых они зависят, и повторно запускает тесты, если какой-либо из этих модулей изменяется.

Единственный уродливый момент, который я действительно хотел бы решить, это то, что каждый раз создаются новый экземпляр PhantomJS и новый сервер Jasmine. updateSpecs это запустить. Я надеялся избежать этого с помощью кода, подобного следующему:

gulp.task('test', function() {
    let testBundler = browserify({
        entries: glob.sync('src/**/*-test.js'),
        cache: {},
        packageCache: {},
    }).plugin(watchify);
    // persist the Jasmine server and PhantomJS browser
    let testServer = jasmineBrowser.headless({driver: 'phantomjs'});
    function updateSpecs() {
        return testBundler.bundle()
            .pipe(vinylStream(jsBundleName))
            .pipe(vinylBuffer())
            .pipe(jasmineBrowser.specRunner({console: true}))
            .pipe(testServer);
    }
    testBundler.on('update', updateSpecs);
    updateSpecs();
});

Увы, это не работает. Сразу после запуска задачи все тесты запускаются нормально, но в следующий раз updateSpecs называется, я получаю write after end Ошибка и задача завершается со статусом 1. Эта ошибка происходит из readable-stream Узловой модуль.

Насколько я понимаю, end событие во время первого запуска updateSpecs листья testServer в состоянии, в котором он не принимает никаких новых входных данных. К сожалению, в документации по потокам Node.js не очень ясно, как это исправить.

Я пытался разорвать цепочку труб в другом месте, но я получил тот же результат, который, кажется, указывает на то, что это универсальное поведение для потоков. Я также пытался остановить end распространение события путем вставки сквозного потока, который не отправлял это событие, но это предотвратило запуск тестов вообще. Наконец я попробовал returnв testServer поток из задачи; это остановило ошибку, но хотя updateSpecs Функция вызывается каждый раз, когда меняются источники, тесты запускаются только при первом запуске задачи. На этот раз testServer кажется, просто игнорировать новый ввод.

Документация gulp-jasmine-browser предполагает, что следующий код будет работать:

var watch = require('gulp-watch');

gulp.task('test', function() {
    var filesForTest = ['src/**/*.js', 'spec/**/*-test.js'];
    return gulp.src(filesForTest)
        .pipe(watch(filesForTest))
        .pipe(jasmineBrowser.specRunner())
        .pipe(jasmineBrowser.server());
});

И далее предполагается, что вы также можете сделать эту работу с Browserify, но это не показано. По-видимому, gulp-watch делает что-то, что заставляет последующие каналы принимать обновленные входные данные позже. Как я могу имитировать это поведение с watchify?

1 ответ

Выпуск GitHub

Как оказалось, в Node.js есть жесткое правило, которое нельзя писать после end событие. К тому же, jasmineBrowser.specRunner(), .server() а также .headless() должен получить end сигнал для того, чтобы на самом деле проверить что-нибудь. Это ограничение унаследовано от официального участника теста Жасмин.

Пример с gulp-watch из README на самом деле тоже не работает, по той же причине. Чтобы это работало, нужно было сделать что-то похожее на рабочую версию моего watchify код в вопросе:

gulp.task('test', function() {
    var filesForTest = ['src/**/*.js', 'spec/**/*-test.js'];
    function runTests() {
        return gulp.src(filesForTest)
            .pipe(jasmineBrowser.specRunner())
            .pipe(jasmineBrowser.server());
    }
    watch(filesForTest).on('add change unlink', runTests);
});

(Я не проверял это, но что-то очень близкое к этому должно работать.)

Итак, какой бы механизм наблюдения вы не использовали, вам всегда нужно будет позвонить .specRunner() а также .server() снова для каждого цикла. Хорошая новость заключается в том, что сервер Jasmine будет использоваться повторно, если вы явно передадите номер порта:

            .pipe(jasmineBrowser.server({port: 8080}));

это также относится к .headless(),

Другие вопросы по тегам