"Писать после завершения": как имитировать глоток с 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 ответ
Как оказалось, в 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()
,