setApplication 中断 ember-qunit 测试上下文

setApplication breaks ember-qunit test context

我最近将 Ember 应用程序从 2.18 升级到 3.13,进展顺利。今天我第一次尝试添加验收测试(之前只有集成/单元测试)但是第一行测试失败:

import { module, test } from "qunit";
import { visit, currentURL } from "@ember/test-helpers";
import { setupApplicationTest } from "ember-qunit";

module("Acceptance | some route", function(hooks) {
  setupApplicationTest(hooks);

  test("visiting /some-route", async function(assert) {
    await visit("/some-route"); // <----- error thrown here

    assert.equal(currentURL(), "/some-route");
  });
});

我看到了几个错误(按此顺序):

Source:     
TypeError: Cannot read property 'lookup' of undefined
    at Object.initialize (http://localhost:4200/assets/my-app.js:10312:28)
    at http://localhost:4200/assets/vendor.js:61627:21
    at Vertices.each (http://localhost:4200/assets/vendor.js:80243:9)
    at Vertices.walk (http://localhost:4200/assets/vendor.js:80157:12)
    at DAG.each (http://localhost:4200/assets/vendor.js:80087:22)
    at DAG.topsort (http://localhost:4200/assets/vendor.js:80095:12)
    at Class._runInitializer (http://localhost:4200/assets/vendor.js:61653:13)
    at Class.runInitializers (http://localhost:4200/assets/vendor.js:61625:12)
    at Class._bootSync (http://localhost:4200/assets/vendor.js:59923:14)
    at Class.boot (http://localhost:4200/assets/vendor.js:59890:14)


Source:     
Error: Cannot call `visit` without having first called `setupApplicationContext`.
    at visit (http://localhost:4200/assets/test-support.js:44177:13)
    at Object._callee$ (http://localhost:4200/assets/tests.js:23:47)
    at tryCatch (http://localhost:4200/assets/vendor.js:12365:40)
    at Generator.invoke [as _invoke] (http://localhost:4200/assets/vendor.js:12591:22)
    at Generator.prototype.<computed> [as next] (http://localhost:4200/assets/vendor.js:12417:21)
    at asyncGeneratorStep (http://localhost:4200/assets/tests.js:6:105)
    at _next (http://localhost:4200/assets/tests.js:8:196)
    at http://localhost:4200/assets/tests.js:8:366
    at new Promise (<anonymous>)
    at Object.<anonymous> (http://localhost:4200/assets/tests.js:8:99)

经过一番挖掘,似乎有什么地方错误地设置了测试上下文。它只是一个空对象:

因此,isApplicationTestContext(context) returns false 并抛出第二个错误。我猜第一个错误是因为应用程序有一些执行查找的初始化程序而引发的。

为了添加此验收测试,我还将 test-helper.js 文件更新为以下内容:

import Application from "../app";
import config from "../config/environment";
import { setApplication } from "@ember/test-helpers";
import { start } from "ember-qunit";

setApplication(Application.create(config.APP));

start();

对于上述文件,所有 测试都失败了,所以似乎 setApplication 导致测试上下文设置不正确?旧的 test-helper.js 文件是这样的:

import resolver from "./helpers/resolver";
import { setResolver } from "@ember/test-helpers";
import { start } from "ember-cli-qunit";

setResolver(resolver);
start();

我试过重新添加 setResolver 调用,但没有任何区别。有没有其他人 运行 使用新的 ember-qunit 语法解决这些问题,或者可能看到我做错了什么?另外,我在 environment.js 文件中设置了 autoboot = false;,这没有什么区别。测试套件还有一两个测试仍然使用较旧的 ember-qunit 语法编写。如有任何帮助,我们将不胜感激!

首先,一些背景故事:

我们的应用程序使用第 3 方库作为指标,使用另一个第 3 方库作为功能标志。每个库都有自己的服务,但我们需要先初始化指标服务,然后才能初始化功能标志服务,因为我们希望 link 分析用户数据以获得每个用户的正确功能标志。功能标志检查在整个应用程序中进行,因此在进行功能标志检查和在网页上的脚本标记中加载分析文件之间出现了竞争条件。

现在解决方案:

弹出此错误的原因:

Source:     
TypeError: Cannot read property 'lookup' of undefined
    at Object.initialize (http://localhost:4200/assets/my-app.js:10312:28)
    at http://localhost:4200/assets/vendor.js:61627:21
    at Vertices.each (http://localhost:4200/assets/vendor.js:80243:9)
    at Vertices.walk (http://localhost:4200/assets/vendor.js:80157:12)
    at DAG.each (http://localhost:4200/assets/vendor.js:80087:22)
    at DAG.topsort (http://localhost:4200/assets/vendor.js:80095:12)
    at Class._runInitializer (http://localhost:4200/assets/vendor.js:61653:13)
    at Class.runInitializers (http://localhost:4200/assets/vendor.js:61625:12)
    at Class._bootSync (http://localhost:4200/assets/vendor.js:59923:14)
    at Class.boot (http://localhost:4200/assets/vendor.js:59890:14)

是因为该应用程序有一个应用程序初始值设定项,它利用私有 Ember API 从容器中执行查找。初始化程序正在执行查找以在检索分析数据之前隐式初始化指标服务,然后初始化功能标志服务。

export function initialize(application) {
  const container = application.__container__; // <-- undefined
  const lookup = container.lookup.bind(application.__container__); // <-- error!
  ...
}

奇怪的是上面的代码在 developmentproduction 环境中工作。此更改似乎是内部 Ember API 的弃用/重新安排的结果,尤其是与容器相关的 API。 See this page for more information.

为了在应用程序初始化程序中访问容器,必须从应用程序实例(即实例初始化程序)中完成。这可能是一个可以接受的解决方案,但我不是 100% 确定我们是否可以从应用程序实例初始化程序中推迟应用程序就绪。

有关应用程序实例初始化器的更多阅读,see here

而是将代码移至应用程序路由的 beforeModel() 挂钩。我还为指标服务添加了一个实例初始化程序,从而缩短了应用程序加载时间。

将初始化程序代码移动到应用程序路由后,现在可以成功构建应用程序,并且验收测试非常有效。 :)