Требование тайм-аутов при тестировании Meteor с Velocity и Jasmine
Довольно плохо знаком с метеоритом, скоростью и жасмином, поэтому не уверен, что я делаю что-то не так, использую жасмин для чего-то, для чего он не предназначен, или это просто так, как он работает.
Я считаю, что мне нужно установить тайм-ауты для почти всех моих тестов, чтобы они прошли. Должно ли это иметь место или я что-то делаю неправильно?
Например, некоторые тесты, которые я запускаю, чтобы проверить сообщения проверки:
describe("add quote validation", function() {
beforeEach(function (done) {
Router.go('addQuote');
Tracker.afterFlush(function(){
done();
});
});
beforeEach(waitForRouter);
it("should show validation when Quote is missing", function(done) {
$('#quote').val('');
$('#author').val('Some author');
Meteor.setTimeout(function(){
$('#addQuoteBtn').click();
}, 500);
Meteor.setTimeout(function(){
expect($('.parsley-custom-error-message').text()).toEqual("Quote can't be empty.");
done();
}, 500);
});
}
1 ответ
Хорошо, у нас была точно такая же проблема, и мы разработали довольно элегантное решение, которое не требует таймаутов и является самым быстрым способом выполнения ваших тестов. По сути, мы используем одну из двух стратегий, в зависимости от того, какие элементы экрана вы ожидаете.
Весь код помещается в tests/mocha/client/lib.coffee, а не на 100% по сравнению с эквивалентом Jasmine, но он должен быть доступен для всего клиентского тестового кода. Я оставил его в Coffeescript, но вы можете скомпилировать его на coffeescript.org в Javascript, он также должен работать нормально.
Если то, что вы делаете (маршрутизация или что-то еще, например, изменение реактивной переменной), вызывает Template
для (пере) рендеринга, вы можете использовать Template.<your_template>.rendered
крючок, чтобы определить, когда закончится рендеринг. Итак, мы добавили следующую функцию в lib.coffee:
@afterRendered = (template,f)->
cb = template.rendered
template.rendered = ->
cb?()
template.rendered = cb
f?()
return
return
Что оно делает? В основном "запоминает" оригинал rendered
обратный вызов и временно заменяет его на тот, который вызывает дополнительную функцию после template
визуализируется и вызывается оригинальный обратный вызов. Он должен выполнять такую уборку, чтобы избежать взлома любого кода, который мог зависеть от rendered
обратный вызов, так как вы в основном работаете непосредственно с кодом Meteor.
В своем тесте вы можете сделать что-то вроде этого:
it.only "should check stuff after routing", (done)->
try
Router.go "<somewhere>"
afterRendered Template.<expected_template>, ->
<your tests here>
done()
catch e
done(e)
Я бы также порекомендовал try-catch, так как я заметил, что асинхронные ошибки не всегда попадают в систему скоростей, просто давая вам ошибку времени ожидания.
Хорошо, тогда есть вещи, которые на самом деле не перерисовываются, а генерируются с помощью JS или с помощью какого-то механизма "показать / скрыть". Для этого вам нужен какой-то тайм-аут, но вы можете уменьшить "временную стоимость" тайм-аута, используя механизм опроса.
# evaluates if a JQuery element is visible or not
$.fn.visible = -> this.length > 0 and this.css('display') isnt 'none'
# This superduper JQuery helper function will trigger a function when an element becomes visible (display != none). If the element is already visible, it triggers immediately.
$.fn.onVisible = (fn,it)->
sel = this.selector
if this.visible()
console.log "Found immediately"
fn?(this)
else
counter = 0
timer = setInterval ->
counter++
el = $(sel)
if el.visible()
fn?(el)
clearInterval timer
console.log "Found on iteration #{counter}"
else
it?(el)
, 50
Вы можете удалить консоль регистрации и вторичные it
Функция итератора, если хотите, они не важны. Это позволяет вам сделать что-то подобное в вашем тесте:
$('#modalId').onVisible (el)->
<tests here>
done()
, (el)->
console.log "Waiting for #{el.selector}"
Вы можете удалить вторую функцию, если хотите, это it
упомянутая выше функция итератора. Однако обратите внимание, что этот конкретный код работает с "display: hidden" в качестве маркера невидимости (Bootstrap делает это). Измените его, если ваш код использует другой механизм, чтобы скрывать / показывать детали.
Работает как шарм для нас!