ember-test-helpers: setupOnError not working
Here are two test cases.
One where a component errors in constructor, and another where it errors in response to a click.
The first can be caught by setupOnError, and ignored in the test suite. đđ»
The second is not caught by setupOnError, and so the test fails. đđ»
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 17 (9 by maintainers)
I got fed up with this long-standing issue, so I decided to invest a bit of time and do some detective work. đ”ïžđ
This occurs, when an error is thrown outside of the Ember run loop.
setupOnerrorworks by hooking intoEmber.onerror, which in turn is called by Backburner (Emberâs backing run loop implementation) when a task in the run loop throws.The error then propagates to the global
window.onerrorhandler orwindow.onunhandledrejection, if itâs async.It still shows up as a global failure in your QUnit test, because QUnit catches these via QUnit.onUncaughtException, like @snewcomer correctly pointed out in the issue that you linked: https://github.com/emberjs/ember-qunit/issues/592#issuecomment-971106445
Running outside of a run loop can easily happen by accident, for instance when you manually add an event listener to an element and donât wrap the listener in
run().And in fact, if you change your
checkaction to throw the error inside a run loop, the test passes!Now the Ember Guides claim that
This would lead me to believe that using
{{on "click" this.check}}and theclicktest helper should just workâą out of the box. So why doesnât it?Ember transparently uses Glimmerâs
{{on}}modifier. Glimmer itself is not integrated with Backburner nor the Ember runloop. It registers the passed in listener as-is without wrapping it inrun()first.I would consider this is a bug, because it violates the promise made in the Ember Guides that you donât need to concern yourself with
runwhen using Emberâs standard tools. It doesnât really matter for real-world apps, because Ember will helpfully wrap calls that schedule tasks into a run loop queue into an implicit autorun loop, if they are not called from inside a run loop. The only negative effect of this is slightly worse performance.This only really becomes an issue in tests, because
Ember.onerroris not set up to handle errors thrown outside of a run loop, like explained above.But the trouble doesnât stop there. Regular ânativeâ DOM events initiated by a user action / the browser are handled asynchronously as opposed to synthetic events, i.e. events triggered manually via
dispatchEvent:clickand any other DOM test helpers firing events usedispatchEventviafireEvent. And sincedispatchEventtriggers the event listeners synchronously, one would hope that, even ifsetupOnerrordoesnât work, the error would at least propagate through toclick:Alas, that also doesnât work: #310, #453, #440
But why? Even though
dispatchEventcalls all listeners synchronously, it doesnât propagate any of the errors they might throw. So there again, the only option is to handle them in a global error handler. As of now, thatâswindow.onerror, which QUnit hooks into and then fails the test with the out of band global failure, like explained above.Ideally though, the handler would be wrapped in a run loop, so that
Ember.onerrorcan catch it instead. That would allow for handling it viasetupOnerror, but theclickhelper still wouldnât throw, because it doesnât hook intoEmber.onerrorto watch for errors thrown during the execution of the event listeners.Made an example: https://github.com/amk221/-ember-unhappy-path-test/pull/1
There is another example of how to do this here: https://github.com/qunitjs/qunit/issues/1419#issuecomment-561739486 â albeit, not contextually ergonomic (nor does it actually work â as QUnitâs properties are readonly (only
QUnit.configis mutable)).So, Iâve opened this issue on the QUnit repo, where I think we should figure out some solution for QUnit v3. https://github.com/qunitjs/qunit/issues/1736
Maybe itâs qunit that needs to provide setupOnError / resetOnError (or similar) for handling this situation.
@amk221 Looks like this is a known issue, there is some discussion in the latter part of this thread in the
ember-qunitrepo, which it looks like you were part of but there has been more discussion since your last comment there. Seems to be currently unresolved.