«Писать после завершения»: как имитировать глоток с watchify? - PullRequest
0 голосов
/ 26 августа 2018

Следующая задача 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 Node.

Насколько я понимаю, событие end во время первого запуска updateSpecs оставляет testServer в состоянии, в котором он не принимает никаких новых входных данных.К сожалению, документация о потоках *1022* 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 Ответ

0 голосов
/ 31 августа 2018

выпуск 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().

...