From 9cdb13602c1873b42920d912df29705eb5ecc683 Mon Sep 17 00:00:00 2001 From: Steve Calvert Date: Thu, 21 Feb 2019 17:38:18 -0800 Subject: [PATCH 1/2] Converting ember-qunit to use test isolation primatives from @ember/test-helpers --- .../ember-qunit/-internal/test-debug-info.js | 133 ---------- .../ember-qunit/test-isolation-validation.js | 13 +- tests/unit/test-debug-info-test.js | 247 ------------------ tests/unit/test-isolation-validation-test.js | 2 +- tests/unit/utils/mock-stable-error.js | 19 -- tests/unit/utils/test-isolation-helpers.js | 62 ----- 6 files changed, 8 insertions(+), 468 deletions(-) delete mode 100644 addon-test-support/ember-qunit/-internal/test-debug-info.js delete mode 100644 tests/unit/test-debug-info-test.js delete mode 100644 tests/unit/utils/mock-stable-error.js delete mode 100644 tests/unit/utils/test-isolation-helpers.js diff --git a/addon-test-support/ember-qunit/-internal/test-debug-info.js b/addon-test-support/ember-qunit/-internal/test-debug-info.js deleted file mode 100644 index 1d483b71..00000000 --- a/addon-test-support/ember-qunit/-internal/test-debug-info.js +++ /dev/null @@ -1,133 +0,0 @@ -import { run } from '@ember/runloop'; -import { assign } from '@ember/polyfills'; - -const PENDING_AJAX_REQUESTS = 'Pending AJAX requests'; -const PENDING_TEST_WAITERS = 'Pending test waiters'; -const SCHEDULED_ASYNC = 'Scheduled async'; -const SCHEDULED_AUTORUN = 'Scheduled autorun'; - -export function getDebugInfo() { - let debugEnabled = run.backburner.DEBUG === true; - let getDebugInfoAvailable = typeof run.backburner.getDebugInfo === 'function'; - - return debugEnabled && getDebugInfoAvailable ? run.backburner.getDebugInfo() : null; -} - -/** - * Encapsulates debug information for an individual test. Aggregates information - * from: - * - the test info provided by qunit (module & name) - * - info provided by @ember/test-helper's getSettledState function - * - hasPendingTimers - * - hasRunLoop - * - hasPendingWaiters - * - hasPendingRequests - * - pendingRequestCount - * - info provided by backburner's getDebugInfo method (timers, schedules, and stack trace info) - */ -export default class TestDebugInfo { - constructor(module, name, settledState, debugInfo = getDebugInfo()) { - this.module = module; - this.name = name; - this.settledState = settledState; - this.debugInfo = debugInfo; - } - - get fullTestName() { - return `${this.module}: ${this.name}`; - } - - get summary() { - if (!this._summaryInfo) { - this._summaryInfo = assign( - { - fullTestName: this.fullTestName, - }, - this.settledState - ); - - if (this.debugInfo) { - this._summaryInfo.autorunStackTrace = - this.debugInfo.autorun && this.debugInfo.autorun.stack; - this._summaryInfo.pendingTimersCount = this.debugInfo.timers.length; - this._summaryInfo.hasPendingTimers = - this._summaryInfo.hasPendingTimers && this._summaryInfo.pendingTimersCount > 0; - this._summaryInfo.pendingTimersStackTraces = this.debugInfo.timers.map( - timer => timer.stack - ); - - this._summaryInfo.pendingScheduledQueueItemCount = this.debugInfo.instanceStack - .filter(q => q) - .reduce((total, item) => { - Object.keys(item).forEach(queueName => { - total += item[queueName].length; - }); - - return total; - }, 0); - this._summaryInfo.pendingScheduledQueueItemStackTraces = this.debugInfo.instanceStack - .filter(q => q) - .reduce((stacks, deferredActionQueues) => { - Object.keys(deferredActionQueues).forEach(queue => { - deferredActionQueues[queue].forEach( - queueItem => queueItem.stack && stacks.push(queueItem.stack) - ); - }); - return stacks; - }, []); - } - } - - return this._summaryInfo; - } - - get message() { - return `\nMore information has been printed to the console. Please use that information to help in debugging.\n\n`; - } - - toConsole(_console = console) { - let summary = this.summary; - - _console.group(summary.fullTestName); - - if (summary.hasPendingRequests) { - _console.log(PENDING_AJAX_REQUESTS); - } - - if (summary.hasPendingWaiters) { - _console.log(PENDING_TEST_WAITERS); - } - - if (summary.hasPendingTimers || summary.pendingScheduledQueueItemCount > 0) { - _console.group(SCHEDULED_ASYNC); - - summary.pendingTimersStackTraces.forEach(timerStack => { - _console.log(timerStack); - }); - - summary.pendingScheduledQueueItemStackTraces.forEach(scheduleQueueItemStack => { - _console.log(scheduleQueueItemStack); - }); - - _console.groupEnd(); - } - - if ( - summary.hasRunLoop && - summary.pendingTimersCount === 0 && - summary.pendingScheduledQueueItemCount === 0 - ) { - _console.log(SCHEDULED_AUTORUN); - - if (summary.autorunStackTrace) { - _console.log(summary.autorunStackTrace); - } - } - - _console.groupEnd(); - } - - _formatCount(title, count) { - return `${title}: ${count}`; - } -} diff --git a/addon-test-support/ember-qunit/test-isolation-validation.js b/addon-test-support/ember-qunit/test-isolation-validation.js index 6a21e224..a89bef3f 100644 --- a/addon-test-support/ember-qunit/test-isolation-validation.js +++ b/addon-test-support/ember-qunit/test-isolation-validation.js @@ -1,7 +1,8 @@ +/* eslint-disable no-console */ import QUnit from 'qunit'; import { run } from '@ember/runloop'; import { waitUntil, isSettled, getSettledState } from '@ember/test-helpers'; -import TestDebugInfo, { getDebugInfo } from './-internal/test-debug-info'; +import { getDebugInfo } from '@ember/test-helpers/-internal/debug-info'; /** * Detects if a specific test isn't isolated. A test is considered @@ -19,16 +20,16 @@ import TestDebugInfo, { getDebugInfo } from './-internal/test-debug-info'; */ export function detectIfTestNotIsolated(test, message = '') { if (!isSettled()) { - let testDebugInfo; + let { debugInfo } = getSettledState(); - testDebugInfo = new TestDebugInfo(test.module.name, test.testName, getSettledState()); - - testDebugInfo.toConsole(); + console.group(`${test.module.name}: ${test.testName}`); + debugInfo.toConsole(); + console.groupEnd(); test.expected++; test.assert.pushResult({ result: false, - message: `${message} ${testDebugInfo.message}`, + message: `${message} ${debugInfo.message}`, }); } } diff --git a/tests/unit/test-debug-info-test.js b/tests/unit/test-debug-info-test.js deleted file mode 100644 index 0a85b0ab..00000000 --- a/tests/unit/test-debug-info-test.js +++ /dev/null @@ -1,247 +0,0 @@ -import { module, test } from 'qunit'; -import { run } from '@ember/runloop'; -import TestDebugInfo, { getDebugInfo } from 'ember-qunit/-internal/test-debug-info'; -import MockStableError, { overrideError, resetError } from './utils/mock-stable-error'; -import { - MockConsole, - getRandomBoolean, - getMockDebugInfo, - getMockSettledState, -} from './utils/test-isolation-helpers'; - -module('TestDebugInfo', function(hooks) { - hooks.beforeEach(function() { - run.backburner.DEBUG = false; - }); - - test('fullTestName returns concatenated test name', function(assert) { - assert.expect(1); - - let testDebugInfo = new TestDebugInfo('foo', 'bar', {}); - - assert.equal(testDebugInfo.fullTestName, 'foo: bar'); - }); - - test('summary returns minimal information when debugInfo is not present', function(assert) { - assert.expect(1); - - let hasPendingTimers = getRandomBoolean(); - let hasPendingWaiters = getRandomBoolean(); - let hasRunLoop = getRandomBoolean(); - let pendingRequestCount = Math.floor(Math.random(10)); - let hasPendingRequests = Boolean(pendingRequestCount > 0); - let testDebugInfo = new TestDebugInfo( - 'foo', - 'bar', - getMockSettledState( - hasPendingTimers, - hasRunLoop, - hasPendingWaiters, - hasPendingRequests, - pendingRequestCount - ) - ); - - assert.deepEqual(testDebugInfo.summary, { - fullTestName: 'foo: bar', - hasPendingRequests, - hasPendingTimers, - hasPendingWaiters, - hasRunLoop, - pendingRequestCount, - }); - }); - - test('summary returns full information when debugInfo is present', function(assert) { - assert.expect(1); - - run.backburner.DEBUG = false; - - let testDebugInfo = new TestDebugInfo( - 'foo', - 'bar', - getMockSettledState(), - getMockDebugInfo(false, 2, [{ name: 'one', count: 1 }, { name: 'two', count: 1 }]) - ); - - assert.deepEqual(testDebugInfo.summary, { - autorunStackTrace: undefined, - fullTestName: 'foo: bar', - hasPendingRequests: false, - hasPendingTimers: false, - hasPendingWaiters: false, - hasRunLoop: false, - pendingRequestCount: 0, - pendingScheduledQueueItemCount: 2, - pendingScheduledQueueItemStackTraces: ['STACK', 'STACK'], - pendingTimersCount: 2, - pendingTimersStackTraces: ['STACK', 'STACK'], - }); - }); - - if (getDebugInfo()) { - module('when using backburner', function(hooks) { - let cancelIds; - - hooks.beforeEach(function() { - cancelIds = []; - overrideError(MockStableError); - }); - - hooks.afterEach(function() { - cancelIds.forEach(cancelId => run.cancel(cancelId)); - - run.backburner.DEBUG = false; - - resetError(); - }); - - test('summary returns full information when debugInfo is present', function(assert) { - assert.expect(1); - - run.backburner.DEBUG = true; - - cancelIds.push(run.later(() => {}, 5000)); - cancelIds.push(run.later(() => {}, 10000)); - - let testDebugInfo = new TestDebugInfo( - 'foo', - 'bar', - getMockSettledState(), - run.backburner.getDebugInfo() - ); - - assert.deepEqual(testDebugInfo.summary, { - fullTestName: 'foo: bar', - hasPendingRequests: false, - hasPendingTimers: false, - hasPendingWaiters: false, - hasRunLoop: false, - pendingRequestCount: 0, - pendingScheduledQueueItemCount: 0, - pendingScheduledQueueItemStackTraces: [], - pendingTimersCount: 2, - pendingTimersStackTraces: ['STACK', 'STACK'], - }); - }); - }); - } - - test('toConsole correctly prints minimal information', function(assert) { - assert.expect(1); - - let mockConsole = new MockConsole(); - - let testDebugInfo = new TestDebugInfo('foo', 'bar', getMockSettledState()); - - testDebugInfo.toConsole(mockConsole); - - assert.deepEqual(mockConsole.toString(), 'foo: bar'); - }); - - test('toConsole correctly prints Scheduled autorun information', function(assert) { - assert.expect(1); - - let mockConsole = new MockConsole(); - - let testDebugInfo = new TestDebugInfo( - 'foo', - 'bar', - getMockSettledState(false, true, false, false, 0), - getMockDebugInfo(new MockStableError('STACK'), 0, null) - ); - - testDebugInfo.toConsole(mockConsole); - - assert.deepEqual( - mockConsole.toString(), - `foo: bar -Scheduled autorun -STACK` - ); - }); - - test('toConsole correctly prints AJAX information', function(assert) { - assert.expect(1); - - let mockConsole = new MockConsole(); - - let testDebugInfo = new TestDebugInfo( - 'foo', - 'bar', - getMockSettledState(false, false, false, true, 2) - ); - - testDebugInfo.toConsole(mockConsole); - - assert.deepEqual( - mockConsole.toString(), - `foo: bar -Pending AJAX requests` - ); - }); - - test('toConsole correctly prints pending test waiter information', function(assert) { - assert.expect(1); - - let mockConsole = new MockConsole(); - - let testDebugInfo = new TestDebugInfo('foo', 'bar', getMockSettledState(false, false, true)); - - testDebugInfo.toConsole(mockConsole); - - assert.deepEqual( - mockConsole.toString(), - `foo: bar -Pending test waiters` - ); - }); - - test('toConsole correctly prints scheduled async information', function(assert) { - assert.expect(1); - - let mockConsole = new MockConsole(); - - let testDebugInfo = new TestDebugInfo( - 'foo', - 'bar', - getMockSettledState(true, true), - getMockDebugInfo(false, 2, [{ name: 'one', count: 1 }, { name: 'two', count: 1 }]) - ); - - testDebugInfo.toConsole(mockConsole); - - assert.deepEqual( - mockConsole.toString(), - `foo: bar -Scheduled async -STACK -STACK -STACK -STACK` - ); - }); - - test('toConsole correctly prints scheduled async information with only scheduled queue items', function(assert) { - assert.expect(1); - - let mockConsole = new MockConsole(); - - let testDebugInfo = new TestDebugInfo( - 'foo', - 'bar', - getMockSettledState(), - getMockDebugInfo(false, 0, [{ name: 'one', count: 1 }, { name: 'two', count: 1 }]) - ); - - testDebugInfo.toConsole(mockConsole); - - assert.deepEqual( - mockConsole.toString(), - `foo: bar -Scheduled async -STACK -STACK` - ); - }); -}); diff --git a/tests/unit/test-isolation-validation-test.js b/tests/unit/test-isolation-validation-test.js index 2930ac96..799ec71f 100644 --- a/tests/unit/test-isolation-validation-test.js +++ b/tests/unit/test-isolation-validation-test.js @@ -2,7 +2,7 @@ import Ember from 'ember'; import { run } from '@ember/runloop'; import { module, test } from 'qunit'; import { installTestNotIsolatedHook } from 'ember-qunit/test-isolation-validation'; -import { getDebugInfo } from 'ember-qunit/-internal/test-debug-info'; +import { getDebugInfo } from '@ember/test-helpers/-internal/debug-info'; import patchAssert from './utils/patch-assert-helper'; diff --git a/tests/unit/utils/mock-stable-error.js b/tests/unit/utils/mock-stable-error.js deleted file mode 100644 index 8f8c4abf..00000000 --- a/tests/unit/utils/mock-stable-error.js +++ /dev/null @@ -1,19 +0,0 @@ -/* eslint-disable no-global-assign */ -/* eslint-disable no-unused-vars */ - -const ERROR = Error; - -Error = ERROR; - -export function overrideError(_Error) { - Error = _Error; -} -export function resetError() { - Error = ERROR; -} -export default class MockStableError { - constructor(message) {} - get stack() { - return 'STACK'; - } -} diff --git a/tests/unit/utils/test-isolation-helpers.js b/tests/unit/utils/test-isolation-helpers.js deleted file mode 100644 index c62eda44..00000000 --- a/tests/unit/utils/test-isolation-helpers.js +++ /dev/null @@ -1,62 +0,0 @@ -const STACK = 'STACK'; - -export class MockConsole { - constructor() { - this._buffer = []; - } - - group(str) { - this._buffer.push(str); - } - - log(str) { - this._buffer.push(str); - } - - groupEnd() {} - - toString() { - return this._buffer.join('\n'); - } -} - -export function getRandomBoolean() { - return Math.random() >= 0.5; -} - -export function getMockDebugInfo(autorun = null, timersCount = 0, queues) { - let debugInfo = {}; - let queueItem = { stack: STACK }; - - if (autorun) { - debugInfo.autorun = autorun; - } - - debugInfo.timers = Array(timersCount).fill(queueItem, 0, timersCount); - - let instanceStack = {}; - debugInfo.instanceStack = [instanceStack]; - - queues && - queues.forEach(queue => { - instanceStack[queue.name] = Array(queue.count).fill(queueItem, 0, queue.count); - }); - - return debugInfo; -} - -export function getMockSettledState( - hasPendingTimers = false, - hasRunLoop = false, - hasPendingWaiters = false, - hasPendingRequests = false, - pendingRequestCount = 0 -) { - return { - hasPendingTimers, - hasRunLoop, - hasPendingWaiters, - hasPendingRequests, - pendingRequestCount, - }; -} From 00e1874cace3c5a85de9b2377d311979749c7750 Mon Sep 17 00:00:00 2001 From: Steve Calvert Date: Fri, 22 Feb 2019 16:25:00 -0800 Subject: [PATCH 2/2] Updating to use public exports of @ember/test-helpers --- addon-test-support/ember-qunit/test-isolation-validation.js | 2 +- tests/unit/test-isolation-validation-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addon-test-support/ember-qunit/test-isolation-validation.js b/addon-test-support/ember-qunit/test-isolation-validation.js index a89bef3f..4b1ea78c 100644 --- a/addon-test-support/ember-qunit/test-isolation-validation.js +++ b/addon-test-support/ember-qunit/test-isolation-validation.js @@ -2,7 +2,7 @@ import QUnit from 'qunit'; import { run } from '@ember/runloop'; import { waitUntil, isSettled, getSettledState } from '@ember/test-helpers'; -import { getDebugInfo } from '@ember/test-helpers/-internal/debug-info'; +import { getDebugInfo } from '@ember/test-helpers'; /** * Detects if a specific test isn't isolated. A test is considered diff --git a/tests/unit/test-isolation-validation-test.js b/tests/unit/test-isolation-validation-test.js index 799ec71f..129331cf 100644 --- a/tests/unit/test-isolation-validation-test.js +++ b/tests/unit/test-isolation-validation-test.js @@ -2,7 +2,7 @@ import Ember from 'ember'; import { run } from '@ember/runloop'; import { module, test } from 'qunit'; import { installTestNotIsolatedHook } from 'ember-qunit/test-isolation-validation'; -import { getDebugInfo } from '@ember/test-helpers/-internal/debug-info'; +import { getDebugInfo } from '@ember/test-helpers'; import patchAssert from './utils/patch-assert-helper';