Ember 并发超时挂在 qunit 中

Ember concurrency timeout hanging in qunit

在 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);
});

一开始以为是我mock请求错误,测试只是超时,其实是正确的轮询数据。去掉这个任务,验收测试正常完成。

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

看到 Unit testing ember-concurrency tasks and yields 但它并没有真正帮助,因为它只处理单元测试。

您没有做错任何事情,这是 ember-并发的常见陷阱。 Ember-concurrency 的 timeout() 函数依赖于 Ember.run.later() 来创建超时,幸运的是或不幸的是,Ember 的测试套件知道使用 Ember.run.later() 创建的所有计时器并将等待所有计时器稳定下来,然后再让测试继续进行。由于您的代码使用无限循环,因此您的计时器永远不会稳定下来,因此测试挂起。在 Ember 指南 here.

中有一小节是关于测试异步代码的

ember-concurrency 文档中有一节是关于这个确切问题的 here。我建议您仔细阅读它以了解他们关于如何解决此问题的建议,尽管当时似乎没有真正优雅的解决方案。

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

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')

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

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

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