diff --git a/addon-test-support/index.js b/addon-test-support/index.js index d69e8def9..9dc872db4 100644 --- a/addon-test-support/index.js +++ b/addon-test-support/index.js @@ -9,6 +9,7 @@ export { default as setupContext, getContext, setContext, unsetContext } from '. export { default as teardownContext } from './teardown-context'; export { default as setupRenderingContext } from './setup-rendering-context'; export { default as teardownRenderingContext } from './teardown-rendering-context'; +export { default as settled } from './settled'; import Ember from 'ember'; Ember.testing = true; diff --git a/addon-test-support/legacy-0-6-x/abstract-test-module.js b/addon-test-support/legacy-0-6-x/abstract-test-module.js index c9f060888..c4bcee6d4 100644 --- a/addon-test-support/legacy-0-6-x/abstract-test-module.js +++ b/addon-test-support/legacy-0-6-x/abstract-test-module.js @@ -2,7 +2,7 @@ import { run } from '@ember/runloop'; import { Promise as EmberPromise, resolve } from 'rsvp'; import { assign, merge as emberMerge } from '@ember/polyfills'; import { _setupPromiseListeners, _teardownPromiseListeners } from '../ext/rsvp'; -import { _setupAJAXHooks, _teardownAJAXHooks } from '../wait'; +import { _setupAJAXHooks, _teardownAJAXHooks } from '../settled'; import { getContext, setContext, unsetContext } from '../setup-context'; import Ember from 'ember'; diff --git a/addon-test-support/settled.js b/addon-test-support/settled.js new file mode 100644 index 000000000..a63d009f7 --- /dev/null +++ b/addon-test-support/settled.js @@ -0,0 +1,98 @@ +/* globals self */ + +import { run } from '@ember/runloop'; + +import { Promise as EmberPromise } from 'rsvp'; +import jQuery from 'jquery'; + +import Ember from 'ember'; + +let requests; +function incrementAjaxPendingRequests(_, xhr) { + requests.push(xhr); +} + +function decrementAjaxPendingRequests(_, xhr) { + // In most Ember versions to date (current version is 2.16) RSVP promises are + // configured to flush in the actions queue of the Ember run loop, however it + // is possible that in the future this changes to use "true" micro-task + // queues. + // + // The entire point here, is that _whenever_ promises are resolved, this + // counter will decrement. In the specific case of AJAX, this means that any + // promises chained off of `$.ajax` will properly have their `.then` called + // _before_ this is decremented (and testing continues) + EmberPromise.resolve().then(() => { + for (let i = 0; i < requests.length; i++) { + if (xhr === requests[i]) { + requests.splice(i, 1); + } + } + }); +} + +export function _teardownAJAXHooks() { + if (!jQuery) { + return; + } + + jQuery(document).off('ajaxSend', incrementAjaxPendingRequests); + jQuery(document).off('ajaxComplete', decrementAjaxPendingRequests); +} + +export function _setupAJAXHooks() { + requests = []; + + if (!jQuery) { + return; + } + + jQuery(document).on('ajaxSend', incrementAjaxPendingRequests); + jQuery(document).on('ajaxComplete', decrementAjaxPendingRequests); +} + +let _internalCheckWaiters; +if (Ember.__loader.registry['ember-testing/test/waiters']) { + _internalCheckWaiters = Ember.__loader.require('ember-testing/test/waiters').checkWaiters; +} + +function checkWaiters() { + if (_internalCheckWaiters) { + return _internalCheckWaiters(); + } else if (Ember.Test.waiters) { + if (Ember.Test.waiters.any(([context, callback]) => !callback.call(context))) { + return true; + } + } + + return false; +} + +export default function settled(_options) { + let options = _options || {}; + let waitForTimers = options.hasOwnProperty('waitForTimers') ? options.waitForTimers : true; + let waitForAJAX = options.hasOwnProperty('waitForAJAX') ? options.waitForAJAX : true; + let waitForWaiters = options.hasOwnProperty('waitForWaiters') ? options.waitForWaiters : true; + + return new EmberPromise(function(resolve) { + let watcher = self.setInterval(function() { + if (waitForTimers && (run.hasScheduledTimers() || run.currentRunLoop)) { + return; + } + + if (waitForAJAX && requests && requests.length > 0) { + return; + } + + if (waitForWaiters && checkWaiters()) { + return; + } + + // Stop polling + self.clearInterval(watcher); + + // Synchronously resolve the promise + run(null, resolve); + }, 10); + }); +} diff --git a/addon-test-support/setup-context.js b/addon-test-support/setup-context.js index 7a28f9fa6..087911799 100644 --- a/addon-test-support/setup-context.js +++ b/addon-test-support/setup-context.js @@ -2,7 +2,7 @@ import { run } from '@ember/runloop'; import { set, setProperties, get, getProperties } from '@ember/object'; import buildOwner from './build-owner'; import { _setupPromiseListeners } from './ext/rsvp'; -import { _setupAJAXHooks } from './wait'; +import { _setupAJAXHooks } from './settled'; let __test_context__; diff --git a/addon-test-support/teardown-context.js b/addon-test-support/teardown-context.js index e40357933..4df98beb6 100644 --- a/addon-test-support/teardown-context.js +++ b/addon-test-support/teardown-context.js @@ -1,6 +1,6 @@ import { run } from '@ember/runloop'; import { _teardownPromiseListeners } from './ext/rsvp'; -import { _teardownAJAXHooks } from './wait'; +import { _teardownAJAXHooks } from './settled'; export default function(context) { let { owner } = context; diff --git a/addon-test-support/wait.js b/addon-test-support/wait.js index f4521926c..a12575082 100644 --- a/addon-test-support/wait.js +++ b/addon-test-support/wait.js @@ -1,98 +1,7 @@ -/* globals self */ - -import { run } from '@ember/runloop'; - -import { Promise as EmberPromise } from 'rsvp'; -import jQuery from 'jquery'; - -import Ember from 'ember'; - -var requests; -function incrementAjaxPendingRequests(_, xhr) { - requests.push(xhr); -} - -function decrementAjaxPendingRequests(_, xhr) { - // In most Ember versions to date (current version is 2.16) RSVP promises are - // configured to flush in the actions queue of the Ember run loop, however it - // is possible that in the future this changes to use "true" micro-task - // queues. - // - // The entire point here, is that _whenever_ promises are resolved, this - // counter will decrement. In the specific case of AJAX, this means that any - // promises chained off of `$.ajax` will properly have their `.then` called - // _before_ this is decremented (and testing continues) - EmberPromise.resolve().then(() => { - for (var i = 0; i < requests.length; i++) { - if (xhr === requests[i]) { - requests.splice(i, 1); - } - } - }); -} - -export function _teardownAJAXHooks() { - if (!jQuery) { - return; - } - - jQuery(document).off('ajaxSend', incrementAjaxPendingRequests); - jQuery(document).off('ajaxComplete', decrementAjaxPendingRequests); -} - -export function _setupAJAXHooks() { - requests = []; - - if (!jQuery) { - return; - } - - jQuery(document).on('ajaxSend', incrementAjaxPendingRequests); - jQuery(document).on('ajaxComplete', decrementAjaxPendingRequests); -} - -var _internalCheckWaiters; -if (Ember.__loader.registry['ember-testing/test/waiters']) { - _internalCheckWaiters = Ember.__loader.require('ember-testing/test/waiters').checkWaiters; -} - -function checkWaiters() { - if (_internalCheckWaiters) { - return _internalCheckWaiters(); - } else if (Ember.Test.waiters) { - if (Ember.Test.waiters.any(([context, callback]) => !callback.call(context))) { - return true; - } - } - - return false; -} - -export default function wait(_options) { - var options = _options || {}; - var waitForTimers = options.hasOwnProperty('waitForTimers') ? options.waitForTimers : true; - var waitForAJAX = options.hasOwnProperty('waitForAJAX') ? options.waitForAJAX : true; - var waitForWaiters = options.hasOwnProperty('waitForWaiters') ? options.waitForWaiters : true; - - return new EmberPromise(function(resolve) { - var watcher = self.setInterval(function() { - if (waitForTimers && (run.hasScheduledTimers() || run.currentRunLoop)) { - return; - } - - if (waitForAJAX && requests && requests.length > 0) { - return; - } - - if (waitForWaiters && checkWaiters()) { - return; - } - - // Stop polling - self.clearInterval(watcher); - - // Synchronously resolve the promise - run(null, resolve); - }, 10); - }); -} +export { + default, + _setupAJAXHooks, + _setupPromiseListeners, + _teardownAJAXHooks, + _teardownPromiseListeners, +} from './settled'; diff --git a/tests/unit/wait-test.js b/tests/unit/legacy-0-6-x/wait-test.js similarity index 98% rename from tests/unit/wait-test.js rename to tests/unit/legacy-0-6-x/wait-test.js index de738c032..f654798d8 100644 --- a/tests/unit/wait-test.js +++ b/tests/unit/legacy-0-6-x/wait-test.js @@ -7,8 +7,8 @@ import wait from 'ember-test-helpers/wait'; import { module, test } from 'qunit'; import hbs from 'htmlbars-inline-precompile'; import Pretender from 'pretender'; -import { fireEvent } from '../helpers/events'; -import hasjQuery from '../helpers/has-jquery'; +import { fireEvent } from '../../helpers/events'; +import hasjQuery from '../../helpers/has-jquery'; import require from 'require'; function ajax(url) {