我在Ember测试中发现了一些不明确的错误消息,没有有用的堆栈跟踪或任何其他信息来找出潜在的原因,但是这种情况需要奖品作为其中最隐晦的就是这些。Ember无法在对象销毁后调用writableChainWatchers
我有这样的灰烬应用,在那里测试是在一个非常奇怪的方式失败:
$ ember test -m "Acceptance | main report" 1 ↵
cleaning up...
Built project successfully. Stored in "/home/username/work/my-project/frontend/tmp/core_object-tests_dist-HinFNKHW.tmp".
ok 1 PhantomJS 2.1 - Acceptance | main report: visiting main home
not ok 2 PhantomJS 2.1 - Acceptance | main report: it changes structure
---
actual: >
false
expected: >
true
stack: >
[email protected]://localhost:7357/!/assets/test-support.js:7199:49
[email protected]://localhost:7357/!/assets/js/vendor.js:54101:22
[email protected]://localhost:7357/!/assets/js/vendor.js:32467:23
[email protected]://localhost:7357/!/assets/js/vendor.js:46036:32
[email protected]://localhost:7357/!/assets/js/vendor.js:73035:19
http://localhost:7357/!/assets/js/vendor.js:73935:28
[email protected]://localhost:7357/!/assets/js/vendor.js:15192:18
[email protected]://localhost:7357/!/assets/js/vendor.js:15260:15
[email protected]://localhost:7357/!/assets/js/vendor.js:15384:20
[email protected]://localhost:7357/!/assets/js/vendor.js:15454:28
[email protected]://localhost:7357/!/assets/js/vendor.js:15577:19
http://localhost:7357/!/assets/js/vendor.js:15873:29
message: >
Error: Assertion Failed: Cannot call writableChainWatchers after the object is destroyed.
Log: |
...
1..2
# tests 2
# pass 1
# skip 0
# fail 1
Not all tests passed.
Error: Not all tests passed.
at EventEmitter.App.getExitCode (/home/username/work/my-project/frontend/node_modules/testem/lib/app.js:434:15)
at EventEmitter.App.exit (/home/username/work/my-project/frontend/node_modules/testem/lib/app.js:189:23)
at /home/username/work/my-project/frontend/node_modules/testem/lib/app.js:103:14
at tryCatcher (/home/username/work/my-project/frontend/node_modules/testem/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/home/username/work/my-project/frontend/node_modules/testem/node_modules/bluebird/js/release/promise.js:510:31)
at Promise._settlePromise (/home/username/work/my-project/frontend/node_modules/testem/node_modules/bluebird/js/release/promise.js:567:18)
at Promise._settlePromise0 (/home/username/work/my-project/frontend/node_modules/testem/node_modules/bluebird/js/release/promise.js:612:10)
at Promise._settlePromises (/home/username/work/my-project/frontend/node_modules/testem/node_modules/bluebird/js/release/promise.js:691:18)
at Async._drainQueue (/home/username/work/my-project/frontend/node_modules/testem/node_modules/bluebird/js/release/async.js:133:16)
at Async._drainQueues (/home/username/work/my-project/frontend/node_modules/testem/node_modules/bluebird/js/release/async.js:143:10)
at Immediate.Async.drainQueues [as _onImmediate] (/home/username/work/my-project/frontend/node_modules/testem/node_modules/bluebird/js/release/async.js:17:14)
at processImmediate [as _immediateCallback] (timers.js:383:17)
注意的错误消息:
Cannot call writableChainWatchers after the object is destroyed.
我的第一个问题是,我怎么能弄清楚什么是导致这个奇怪的错误,当我得到的堆栈跟踪是什么,但有帮助。这不仅不利于获得构建的vendor.js
的这些疯狂行数,而且堆栈跟踪中也没有任何内容来自我的应用程序本身。所以没有线号可以帮助我。
另外,在dev或生产环境中运行应用程序时,不会发生此错误情况。 这只是在测试环境中发生。
最后,也许更重要的是:我意识到错误的原因与状态从一个测试泄漏到另一个测试有关。在该测试文件中,您可以看到有两个测试。第一个通过,但第二个失败。当我评论第一个时,为了专注于唯一失败的测试,事实证明它不会失败。当我在文件中交换这两个测试的顺序时,那么失败的那个,以前是次要的,现在它是第一个没有失败的测试。相反,当它是第一个时,它正在通过,现在是最后一次失败。
更新
我有关于发生此错误的条件的更多信息。
我在应用程序中精确定位了代码行,并在测试中引发了这一行。它看起来像这样:
Ember.run(() => this.set('value', value));
这行代码是在我的应用程序使用compute
方法内。这位助手的观察员在服务中的某些属性更改其值时调用this.recompute()
。很像是显示here。
引发此错误的实际代码不是this.set
调用。我删除它,代码仍然会发生。这仅仅是Ember.run
的罪魁祸首。但是,当我直接调用this.set
而未将其包装在Ember.run
中时,也会发生该错误。为了完全清楚,任何以下三行代码的提出同样的错误:
Ember.run(() => this.set('value', value));
Ember.run(() => {});
this.set('value', value);
我必须马上修复它是包装一个try/catch
内符合空catch
块,默默的唯一途径忽略错误。
我还追踪了引起这个错误的ember.js中的代码行。你可以看看它here。我仍然希望有人能够弄清楚这一点。
感谢AlexMA。我会更深入地探讨你提到的这个附加组件。我知道你在第一段中提到的这个问题,但是在这种情况下并不完全相同,原因有两个:首先,当它是在一个被破坏的对象中设置值时,错误将会像“yo called”集合'在一个被毁坏的物体上“。但是这个“可写的观察者”事物使得它更加怪异和低层次。其次,无论事情发展得有多快,一些国家从一次测试漏到另一次测试是不可接受的。如果测试通过隔离运行时,它应该在套件中运行时通过。 – Ernesto
我在上面添加了更多相关信息,以防情况下对诊断这种情况有用。 – Ernesto
如果您尝试在'if(!this.isDestroyed){...}'中包装代码,该怎么办?或者试着在那里包装'recompute'电话?在这一点上,我有点超出我的深度,并会在我的开发控制台中打开“暂停捕捉异常”,或尝试在Ember松弛通道中找到一些帮助。 – AlexMA