Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding tests not settled detection support in tests #314

Merged
merged 8 commits into from
Feb 23, 2018
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions addon-test-support/ember-qunit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
teardownApplicationContext,
validateErrorHandler,
} from '@ember/test-helpers';
import { detectIfNotSettled, reportIfNotSettled } from './tests-not-settled-detection';

export function setResolver() {
deprecate(
Expand Down Expand Up @@ -228,6 +229,11 @@ export function setupEmberOnerrorValidation() {
});
}

export function setupTestsNotSettledDetection() {
QUnit.testDone(detectIfNotSettled);
QUnit.done(reportIfNotSettled);
}

/**
@method start
@param {Object} [options] Options to be used for enabling/disabling behaviors
Expand All @@ -243,6 +249,8 @@ export function setupEmberOnerrorValidation() {
back to `false` after each test will.
@param {Boolean} [options.setupEmberOnerrorValidation] If `false` validation
of `Ember.onerror` will be disabled.
@param {Boolean} [options.setupTestsNotSettledDetection] If `false` tests not settled detection
will be disabled.
*/
export function start(options = {}) {
if (options.loadTests !== false) {
Expand All @@ -265,6 +273,10 @@ export function start(options = {}) {
setupEmberOnerrorValidation();
}

if (options.setupTestsNotSettledDetection !== false) {
setupTestsNotSettledDetection();
}

if (options.startTests !== false) {
startTests();
}
Expand Down
46 changes: 46 additions & 0 deletions addon-test-support/ember-qunit/tests-not-settled-detection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { run } from '@ember/runloop';
import { isSettled } from '@ember/test-helpers';

const TESTS_NOT_SETTLED = [];

/**
* Detects if a specific test hasn't reached the settled state. A test is considered
* settled if it:
*
* - has no pending timers
* - is not in a runloop
* - has no pending AJAX requests
* - has no pending test waiters
*
* @param {Object} testInfo
* @param {string} testInfo.module The name of the test module
* @param {string} testInfo.name The test name
*/
export function detectIfNotSettled({ module, name }) {
if (!isSettled()) {
TESTS_NOT_SETTLED.push(`${module}: ${name}`);
run.cancelTimers();
}
}

/**
* Reports if a test is not considered settled. Please see above for what
* constitutes settledness.
*
* @throws Error if tests have not settled
*/
export function reportIfNotSettled() {
if (TESTS_NOT_SETTLED.length > 0) {
let leakyTests = TESTS_NOT_SETTLED.slice();
TESTS_NOT_SETTLED.length = 0;

throw new Error(getMessage(leakyTests.length, leakyTests.join('\n')));
}
}

export function getMessage(testCount, testsToReport) {
return `TESTS HAVE UNSETTLED ASYNC BEHAVIOR
The following (${testCount}) tests have one or more of pending timers, pending AJAX requests, pending test waiters, or are still in a runloop: \n
${testsToReport}
`;
}
17 changes: 10 additions & 7 deletions testem.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ module.exports = {
'Chrome'
],
browser_args: {
Chrome: [
'--disable-gpu',
'--headless',
'--no-sandbox',
'--remote-debugging-port=9222',
'--window-size=1440,900'
]
Chrome: {
mode: 'ci',
args: [
'--disable-gpu',
'--headless',
'--no-sandbox',
'--remote-debugging-port=9222',
'--window-size=1440,900'
]
}
}
};
74 changes: 74 additions & 0 deletions tests/unit/setup-tests-not-settled-detection-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import Ember from 'ember';
import { run } from '@ember/runloop';
import { module, test } from 'qunit';
import {
detectIfNotSettled,
reportIfNotSettled,
getMessage,
} from 'ember-qunit/tests-not-settled-detection';

module('setupTestsNotSettledDetection', function(hooks) {
hooks.beforeEach(function() {
this.cancelId = 0;

this._waiter = () => {
return !this.isWaiterPending;
};

// In Ember < 2.8 `registerWaiter` expected to be bound to
// `Ember.Test` 😭
//
// Once we have dropped support for < 2.8 we should swap this to
// use:
//
// import { registerWaiter } from '@ember/test';
Ember.Test.registerWaiter(this._waiter);
});

hooks.afterEach(function() {
Ember.Test.unregisterWaiter(this._waiter);

run.cancel(this.cancelId);
});

test('reportIfNotSettled does not throw when test has settled', function(assert) {
assert.expect(1);

detectIfNotSettled({ module: 'foo', name: 'bar' });
reportIfNotSettled();

assert.ok(true);
});

test('reportIfNotSettled throws when test has not settled pending timers', function(assert) {
assert.expect(1);

this.cancelId = run.later(() => {}, 10);

detectIfNotSettled({ module: 'foo', name: 'bar' });

assert.throws(
function() {
reportIfNotSettled();
},
Error,
getMessage(1, 'foo: bar')
);
});

test('reportIfNotSettled throws when test has not settled test waiters', function(assert) {
assert.expect(1);

this.isWaiterPending = true;

detectIfNotSettled({ module: 'foo', name: 'bar' });

assert.throws(
function() {
reportIfNotSettled();
},
Error,
getMessage(1, 'foo: bar')
);
});
});