Uncaught exception from browser breaks tests

I’m using ember-mocha and when I run my tests with Chrome I intermittently get an exception like this:

Error: Uncaught NetworkError: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'https://localhost:7357/assets/ace/worker-json.js' failed to load. (blob:https://localhost:7357/244407ad-35de-4f79-9f91-3e5f494ee52c:1)
         at global.onerror (https://localhost:7357/assets/test-support.js:13994:10)

That generally causes the next test to fail with:

Assertion Failed: You cannot use the same root element (DIV) multiple times in an Ember.Application
  stack: >
    Error: Assertion Failed: You cannot use the same root element (DIV) multiple times in an Ember.Application

Then a series of tests after that all fail in the “before each” or “after each” hooks that aren’t from my tests, but I assume from ember-mocha. They complain about seemingly random things like Cannot read property 'call' of undefined, Cannot use 'in' operator to search for 'destroy' in undefined and then it just gives up running the remaining tests.

If I run it a few times generally it will pass all the tests and the Uncaught NetworkError never shows up.

I’ve checked the content-type on https://localhost:7357/assets/ace/worker-json.js and it’s “application/javascript” which seems fine. How can I handle the Uncaught NetworkError better or stop it from happening at all?

Does your app use importScripts directly or is this happening in some addon?

When dealing with web workers in tests you may need to be extra careful to reset the worker’s state gracefully between tests. For example, if the web worker is getting shut down maybe that cancels its pending network requests and causes you to see this exception (I’m just speculating here).

The import is happening in the ember-ace addon. I think the error is due to the render test finishing too quickly and the browser cancels the fetch, and throws the NetworkError. I can see the canceled request in the devtools.

Is there a way to change the broccolli serving middleware to add caching headers to certain assets? I think if it could cache this addon file instead of having to fetch it every time that would help.

This hack is roughly what I’m doing now and that seems to help.

const sleep = ms => new Promise(r => setTimeout(r, ms))

await render(hbs`{{live-config model=model}}`);
await sleep(50)
expect($('.ace_text-input')).to.have.length(1);

You should find a way to make the tests wait for the worker to do its thing. Otherwise you can have other problems than just this network error (consider what happens if a new test has started while the worker from the old test is still sending messages back).

Instead of sleeping an arbitrary time, you can use waitFor to detect changes in the DOM, if that’s a reliable way to tell if this particular component has finished what it was doing.

You could also ask directly as an issue on ember-ace. I think it’s reasonable for an addon to explain what the asynchrony requirements are for testing it safely.

I’ll follow up with the ember-ace folks. Separately any ideas why this one uncaught exception rampaged through the remaining before each/after each hooks? Inside the tests this would just point to the window object. A lot of the variable scaffolding the ember test sets up were just undefined.

My guess is it has to do with how mocha handles exceptions vs qunit, but I haven’t dug any further.

Once you lose control of asynchrony in a test suite, most bets are off. For example, the test may have finished and torn down all its state, but then the asynchronous code that’s still running in the worker triggers a callback that calls back into the test again, which then finds its state all missing.