4

在 Ember 中,我有一个组件可以启动永无止境的轮询以保持一些数据是最新的。像这样:

export default Component.extend({
  pollTask: task(function * () {
    while(true) {
      yield timeout(this.get('pollRate'));
      this.fetchSomeData();
    }
  }).on('init')
})

这会导致预先存在的验收测试卡在此任务中并永远运行,即使它应该异步运行。测试看起来像这样:

test('my test', async function(assert) {
  mockFindRecord(make('fetched-model'));

  await visit('/mypage'); // gets stuck here
  await typeIn('input', 'abc123');

  assert.ok(somethingAboutThePage);
});

起初我以为我嘲笑了这个请求是错误的,并且测试只是超时了,但实际上它是正确地轮询数据。删除此任务使验收测试正常完成。

手动测试似乎工作正常,没有任何卡住。为什么会发生这种情况,解决这个问题的正确方法是什么?

看到单元测试 ember-concurrency 任务和产量,但它并没有真正帮助,因为它只处理单元测试。

4

1 回答 1

3

您没有做错任何事情,这是 ember-concurrency 的常见问题。Ember-concurrency 的timeout()功能依赖于Ember.run.later()创建超时,幸运或不幸的是,Ember 的测试套件知道所有创建的计时器,Ember.run.later()并在让测试继续之前等待所有计时器稳定。由于您的代码使用无限循环,因此您的计时器将永远不会稳定,因此测试会挂起。在此处的 Ember 指南中有一个关于测试异步代码的不错的小部分。

在 ember-concurrency 文档中有一个关于这个确切问题的部分。我建议你仔细阅读它,看看他们关于如何解决这个问题的建议,尽管当时似乎没有真正优雅的解决方案。

让这个不挂起的最快和可能最简单的方法是检查应用程序是否正在测试(粗,我知道):

pollTask: task(function * () {
    while(true) {
      yield timeout(this.get('pollRate'));
      this.fetchSomeData();
      if (Ember.testing) return; // stop polling to prevent tests from hanging
    }
  }).on('init')

您还可以尝试Ember.run.cancelTimers()tests/helpers/start-app.js文件中调用 to(该部分中的另一个建议):

window._breakTimerLoopsId = Ember.run.later(() => {
  Ember.run.cancelTimers();
}, 500);

但它似乎没有出现在 API 文档中,所以我个人不会依赖它。

于 2019-10-23T16:06:15.553 回答