Skip to content

Commit

Permalink
Expose settled helper function.
Browse files Browse the repository at this point in the history
* Rename `wait` to `settled`
* Ensure existing `import wait from 'ember-test-helpers/wait'` code works properly
* Export `settled` as public API from the main `index.js`
* Move existing `wait` tests into `legacy-0-6-x` folder

Primary reasoning for the rename from `wait` to `settled`:

```js

test('can do xyz', async function(assert) {
  await this.render(hbs`{{some-thing}}`);
  await click('.some-thing');
  await wait(); // <- WAT?!?!!?
});
```

This looks much better:

```js
test('can do xyz', async function(assert) {
  await this.render(hbs`{{some-thing}}`);
  await click('.some-thing');
  await settled();
});
```
  • Loading branch information
rwjblue committed Oct 16, 2017
1 parent a700f19 commit 0a83ee3
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 103 deletions.
1 change: 1 addition & 0 deletions addon-test-support/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
2 changes: 1 addition & 1 deletion addon-test-support/legacy-0-6-x/abstract-test-module.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
98 changes: 98 additions & 0 deletions addon-test-support/settled.js
Original file line number Diff line number Diff line change
@@ -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);
});
}
2 changes: 1 addition & 1 deletion addon-test-support/setup-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -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__;

Expand Down
2 changes: 1 addition & 1 deletion addon-test-support/teardown-context.js
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
105 changes: 7 additions & 98 deletions addon-test-support/wait.js
Original file line number Diff line number Diff line change
@@ -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';
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 0a83ee3

Please sign in to comment.