使用对测试友好的scheduleOnce,ember的正确方法是什么?

时间:2015-02-26 15:18:20

标签: ember.js

通常,我们需要在渲染完成后安排更新以响应属性更改。这是一个例子:

  page_changed: function() {
    Ember.run.scheduleOnce('afterRender', this, this.scroll);
  }.observes('current_page')

这不适用于测试,因为在调用scheduleOnce时没有runloop。我们可以简单地将scheduleOnce包裹在Ember.run

  page_changed: function() {
    Ember.run(function() {
      Ember.run.scheduleOnce('afterRender', that, that.scroll);
    });
  ).observes('current_page')

..但我被告知这不是正确的方法。我以为我会伸手去拿一些其他的想法。

此处参考是我在ember.js#10536

中打开的问题

3 个答案:

答案 0 :(得分:1)

根据@ StefanPenner的评论看起来这样做是可行的。而不是修改应用程序代码本身只需使用Ember.run

包装渲染调用
test('it renders', function() {
  expect(2);

  var component = this.subject();
  var that = this;

  equal(component._state, 'preRender');

  // Wrapping render in Ember.run
  Ember.run(function() {
    that.render();
  });

  equal(component._state, 'inDOM');
});

答案 1 :(得分:1)

测试中应用程序的入口点需要Ember.run。例如

test('foo', function() {
  user.set('foo', 1); // may have side-affects
});

test('foo', function() {
  Ember.run(function() {
    user.set('foo', 1);
  });
});

为什么需要这个? Ember.run包装了由click / user-actions / ajax等触发的所有调用栈的根。为什么?运行循环允许ember批处理

在编写单元测试时,我们正在“伪造”用户或网络操作,将您想要“批处理”的更改组包含在一起并不明显。

我们可以将Ember.run视为创建批处理或更改事务的方法。最终我们使用它来批量DOM读/写以理想的方式与DOM交互。

虽然在你掌握它之前可能会感到沮丧,但它是创建简洁和确定性测试的好方法。例如:

test('a series of grouped things', function() { 

  Ember.run(function() {
    component.set('firstName', 'Stef');
    component.set('lastName', 'Penner');
    // DOM isn't updated yet
  });

  // DOM is updated;
  // assert the DOM is updated

   Ember.run(function() {
    component.set('firstName', 'Kris');
    component.set('lastName', 'Selden');
    // DOM isn't updated yet, (its still Stef Penner)
  });

  // DOM is once again updated, its now Kris Selden.
});

为什么这很酷? Ember为我们提供了细粒度的控制,这使我们不仅可以非常轻松地单独测试应用程序的各个方面,还可以测试基于用户或基于ajax推送的操作的序列,而无需合并这些方面。

随着时间的推移,我们希望改善测试助手和清晰度。

答案 2 :(得分:0)

  

..但我被告知这不是正确的方法。

原因是在执行回调时需要Ember.run调用 ,而不是在调度时。像这样:

Ember.run.scheduleOnce('afterRender', function() {
    Ember.run(function() {
        that.scroll();
    });
});

在您的代码中,在调度回调时调用Ember.run。这可能是不必要的,因为您可能已经在运行循环中。我的版本确保在调用回调时,即使运行循环很久以前完成,也会启动另一个运行循环并在运行循环中调用that.scroll()。这有道理吗?