Ember 3.0 接受重定向测试永远挂起

Ember 3.0 acceptance redirect test hangs forever

我在 modern RFC 268 format 中为 Ember 3.0 编写了一个简单的验收测试。

测试是针对一个页面,如果用户未经身份验证,URL 会立即重定向到 /login

...

module('Acceptance | index', function (hooks) {
  setupApplicationTest(hooks);

  test('visiting / logged out', async function(assert) {
    assert.expect(1);

    // Test hangs here forever.
    await visit('/');

    assert.equal(currentURL(), '/login');
  });
});

此测试使用旧格式 moduleForAcceptance 时效果很好。

不幸的是,此测试在 Ember 3.0 中永远挂起。我在这里错过了什么吗?有没有更好的方法来测试重定向?

控制台没有错误,添加了一些console.log语句表明await是测试挂起的地方。

我找到了失败的原因。我有一个 Ember mixin,我用它来增强我所有的 routes。 mixin 检查用户是否经过身份验证,并根据需要重定向到 /login

export default Mixin.create({
  session: service(),

  beforeModel() {
    this._super(...arguments);

    return new EmberPromise((resolve) => {
      if (authenticated) {
        resolve();
        return;
      }

      this.transitionTo('login');
    });
  }
});

你会注意到,如果 authenticated 是假的,我没有解决。这适用于我的应用程序和 2.18.

中的测试语法

docs say 以下关于我在 mixin 中覆盖的钩子的内容。

returns Any | Promise

if the value returned from this hook is a promise, the transition will pause until the transition resolves. Otherwise, non-promise return values are not utilized in any way.

对我来说,关于 "non-promise return values" 的一点暗示我 应该 能够做我正在做的事情。特别是考虑到这在 2.18 中有效,但我想知道这是否是 "wow, how did that ever work in the first place" 场景中的一种。显然这种语法在 3.0 中不起作用。因为在测试时过渡会永远暂停。

我的答案是确保我总是resolve/reject某事。在这种情况下,我必须添加一个明确的 reject(),这样 promise 链就不会挂起。

export default Mixin.create({
  session: service(),

  beforeModel() {
    this._super(...arguments);

    return new EmberPromise((resolve) => {
      if (authenticated) {
        resolve();
        return;
      }

      this.transitionTo('login');
      reject();
    });
  }
});

我的测试很好。正是 mixin 需要更新才能与 Ember 3.0 和最新的测试语法一起正常工作。

如果用户是 authenticated,问题不是您的 beforeModel 钩子解决的问题,而是您的 Promise 根本没有解决。您不必 return Promise in beforeModel 挂钩,但如果您 return 挂钩,它将阻止转换,直到 Promise 得到解决。由于不清楚如果在当前转换被阻止时调用另一个转换(不是 resolved/rejected 承诺),ember 应该如何反应,解决或拒绝是正确的行为。请记住,在 Promise return 中,除了结束执行之外没有任何其他含义。它不会解决或拒绝您的承诺。

visit() 可能挂起的另一个原因是它等待像 Ember.run.later() 这样的计时器解决,导致应用程序某处出现不明显的阻塞。

AlphaGit on github summarized the issue 举例说明:

Most of the actions that Ember.testing executes (like visit) will append to a promise that gets executed action after action in the right order. In order to pass to the next action, Ember.testing makes sure that there is nothing pending, so that the step can be considered complete and move forward.

Along with the things that are tested for, pending AJAX requests are verified, and also scheduled timers. These timers may arise from, you guessed it, Ember.run.later calls. If for any reason you would have in your code periodic Ember.run.later methods (so that one is always waiting to be excuted), it's likely that you'll face this issue.

I've faced it myself in a similar scenario: My server returns a OAuth access token with 100 hours until expired, so ember-simpleAuth registers a call close to the expiration time with Ember.run.later to refresh the token. This will, however, prevent the test from moving along. My specific situations has been fixed in further versions but any similar behavior will reproduce the issue (which is likely a conclusion of the current design of Ember.testing).

以下是用户 运行 遇到类似问题的其他几个示例: