From c260ad050be57e1c9055e79db97c35b21a5bd101 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 2 Nov 2018 19:40:12 -0400 Subject: [PATCH] Ensure `await settled()` avoids creating an autorun. --- .../@ember/test-helpers/-utils.ts | 53 +++++++++++++++++-- .../@ember/test-helpers/wait-until.ts | 3 +- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/-utils.ts b/addon-test-support/@ember/test-helpers/-utils.ts index eaebe2b8c..91e803ff4 100644 --- a/addon-test-support/@ember/test-helpers/-utils.ts +++ b/addon-test-support/@ember/test-helpers/-utils.ts @@ -1,5 +1,43 @@ /* globals Promise */ -import { Promise as RSVPPromise } from 'rsvp'; + +import RSVP from 'rsvp'; +import Ember from 'ember'; +import { run } from '@ember/runloop'; +import hasEmberVersion from './has-ember-version'; + +const backburner = (run as any).backburner; + +export class _Promise extends RSVP.Promise {} + +RSVP.configure('async', (callback, promise) => { + if (promise instanceof _Promise) { + if (typeof Promise !== 'undefined') { + // use real native promise semantics whenever possible + Promise.resolve().then(() => callback(promise)); + } else { + // fallback to using RSVP's natural `asap` (**not** the fake + // one configured by Ember...) + RSVP.asap(callback, promise); + } + } else { + // this is the default behaviors from Ember: + // https://github.com/emberjs/ember.js/blob/v3.4.6/packages/ember-testing/lib/ext/rsvp.js + + // if schedule will cause autorun, we need to inform the test adapter + if (Ember.testing && !backburner.currentInstance) { + let adapter = Ember.Test.adapter as any; + + adapter && adapter.asyncStart(); + + backburner.schedule('actions', () => { + adapter && adapter.asyncEnd(); + callback(promise); + }); + } else { + backburner.schedule('actions', () => callback(promise)); + } + } +}); export const nextTick: Function = typeof Promise === 'undefined' ? setTimeout : cb => Promise.resolve().then(cb); @@ -10,9 +48,16 @@ export const futureTick = setTimeout; @returns {Promise} Promise which can not be forced to be ran synchronously */ export function nextTickPromise() { - return new RSVPPromise(resolve => { - nextTick(resolve); - }); + // Ember 3.4 removed the auto-run assertion, in 3.4+ we can (and should) avoid the "psuedo promisey" run loop configuration + // for our `nextTickPromise` implementation. This allows us to have real microtask based next tick timing... + if (hasEmberVersion(3,4)) { + return _Promise.resolve(); + } else { + // on older Ember's fallback to RSVP.Promise + a setTimeout + return new RSVP.Promise(resolve => { + nextTick(resolve); + }); + } } /** diff --git a/addon-test-support/@ember/test-helpers/wait-until.ts b/addon-test-support/@ember/test-helpers/wait-until.ts index 1b430300d..f5af37d13 100644 --- a/addon-test-support/@ember/test-helpers/wait-until.ts +++ b/addon-test-support/@ember/test-helpers/wait-until.ts @@ -1,5 +1,4 @@ -import { Promise } from 'rsvp'; -import { futureTick } from './-utils'; +import { futureTick, _Promise as Promise } from './-utils'; const TIMEOUTS = [0, 1, 2, 5, 7]; const MAX_TIMEOUT = 10;