fix(specs): change spec scheduler back to setTimeout

Summary:
Adds a new `npm run test-window` that will launch specs in a window so you
can use the debugger

The spec window wouldn't close because `onbeforeunload` was unnecessarily
preventing close. This circumvents this in spec mode.

Most significantly I discovered we can't use the synchronous timer for the
promise scheduler anymore. Suppose you do:

```
it('should error', async () => {
  try {
    await doSomething()
    throw new Error("doSomething should have thrown!")
  } catch (err) {
    expect(err.message).toMatch(/my message/)
  }
})
```

The way async/await is transpiled, when `doSomething` throws, the error
will propagate all the way back up to the uncaughtPromiseException handler
before the `catch` gets called and registered. The transpilation method
assumes that when the function gets executed it can synchrously advance
beyond the call before the `then` or `catch` resolve. When the promise
scheduler is synchronous this doesn't happen.

I chose to use `setTimeout` instead of `process.nextTick` or
`setImmediate` as the promise scheduler. `setTimeout` seems to work better
with Chrome's async function call stacks. `nextTick` and `setImmediate`,
being Node methods, skip Chrome's async watchers.

Test Plan:
I talked with Juan about these changes, in an upcoming diff he will be
testing these in the context of our broader test suite.

Reviewers: mark, khamidou, halla, spang, juan

Reviewed By: juan

Differential Revision: https://phab.nylas.com/D3779
This commit is contained in:
Evan Morikawa 2017-01-25 17:43:11 -05:00
parent 2fe1368aa9
commit 14514a3413
4 changed files with 5 additions and 2 deletions

View file

@ -109,6 +109,7 @@
"packageDependencies": {},
"scripts": {
"test": "electron . --test --enable-logging",
"test-window": "electron . --test=window --enable-logging",
"start": "electron . --dev --enable-logging",
"lint": "script/grunt lint",
"build": "script/grunt build",

View file

@ -151,7 +151,7 @@ class N1GuiReporter extends React.Component
</div>
onReloadSpecs: =>
require('electron').ipcRenderer.send('call-webcontents-method', 'reload')
require('electron').remote.getCurrentWindow().reload()
class SuiteResultView extends React.Component

View file

@ -33,6 +33,7 @@ class TimeOverride
@enableSpies = =>
window.advanceClock = @advanceClock
window.originalSetTimeout = window.setTimeout
window.originalSetInterval = window.setInterval
spyOn(window, "setTimeout").andCallFake @_fakeSetTimeout
spyOn(window, "clearTimeout").andCallFake @_fakeClearTimeout
@ -47,7 +48,7 @@ class TimeOverride
@_setPromiseScheduler: =>
@originalPromiseScheduler ?= Promise.setScheduler (fn) =>
fn()
window.originalSetTimeout(fn, 0)
@disableSpies = =>
window.advanceClock = null

View file

@ -35,6 +35,7 @@ class WindowEventHandler
window.dispatchEvent(new Event('scroll-touch-end'))
window.onbeforeunload = =>
if NylasEnv.inSpecMode() then return undefined
# Don't hide the window here if we don't want the renderer process to be
# throttled in case more work needs to be done before closing