使用 Velocity 和 Jasmine 测试 Meteor 时需要超时
Requiring timeouts when testing Meteor with Velocity and Jasmine
对 meteor、velocity 和 jasmine 还很陌生,所以不确定我是否做错了什么,将 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);
});
}
好的,我们遇到了完全相同的问题并设计了一个非常优雅的解决方案,它不需要超时并且是 运行 测试的最快方法。基本上,我们使用两种策略之一,具体取决于您等待的屏幕元素。
所有代码都进入 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
它有什么作用?它基本上 "remembers" 原始的 rendered
回调和 临时 将其替换为调用额外函数 after 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 或某种 "show/hide" 机制生成的。为此,您确实需要某种超时,但您可以通过使用轮询机制来减少超时的 "time cost"。
# 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 执行此操作)。如果您的代码对 hide/show 部分使用另一种机制,请更改它。
对我们来说就像一个魅力!
对 meteor、velocity 和 jasmine 还很陌生,所以不确定我是否做错了什么,将 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);
});
}
好的,我们遇到了完全相同的问题并设计了一个非常优雅的解决方案,它不需要超时并且是 运行 测试的最快方法。基本上,我们使用两种策略之一,具体取决于您等待的屏幕元素。
所有代码都进入 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
它有什么作用?它基本上 "remembers" 原始的 rendered
回调和 临时 将其替换为调用额外函数 after 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 或某种 "show/hide" 机制生成的。为此,您确实需要某种超时,但您可以通过使用轮询机制来减少超时的 "time cost"。
# 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 执行此操作)。如果您的代码对 hide/show 部分使用另一种机制,请更改它。
对我们来说就像一个魅力!