Skip to content

Commit

Permalink
Core: Adding promise handling on qunit callbacks
Browse files Browse the repository at this point in the history
  • Loading branch information
step2yeung committed Aug 23, 2018
1 parent a3b1463 commit 6711d27
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 49 deletions.
1 change: 1 addition & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ module.exports = function( grunt ) {
"test/reorderError1.html",
"test/reorderError2.html",
"test/callbacks.html",
"test/callbacks-promises.html",
"test/events.html",
"test/events-in-test.html",
"test/logs.html",
Expand Down
12 changes: 8 additions & 4 deletions src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ function scheduleBegin() {
}
}

function unblockAndAdvanceQueue() {
config.blocking = false;
ProcessingQueue.advance();
}

export function begin() {
var i, l,
modulesLog = [];
Expand Down Expand Up @@ -171,11 +176,10 @@ export function begin() {
runLoggingCallbacks( "begin", {
totalTests: Test.count,
modules: modulesLog
} );
} ).then( unblockAndAdvanceQueue );
} else {
unblockAndAdvanceQueue();
}

config.blocking = false;
ProcessingQueue.advance();
}

exportQUnit( QUnit );
Expand Down
9 changes: 3 additions & 6 deletions src/core/logging.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ export function registerLoggingCallbacks( obj ) {
}

export function runLoggingCallbacks( key, args ) {
var i, l, callbacks;

callbacks = config.callbacks[ key ];
for ( i = 0, l = callbacks.length; i < l; i++ ) {
callbacks[ i ]( args );
}
var callbacks = config.callbacks[ key ];
var promises = callbacks.map( callback => Promise.resolve( callback( args ) ) );
return Promise.all( promises );
}
25 changes: 19 additions & 6 deletions src/core/processing-queue.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,38 @@ function advance() {
}

/**
* Advances the taskQueue to the next task if it is ready and not empty.
* Advances the taskQueue with an increased depth
*/
function advanceTaskQueue() {
const start = now();
config.depth = ( config.depth || 0 ) + 1;

while ( taskQueue.length && !config.blocking ) {
processTaskQueue( start );

config.depth--;
}

/**
* Process the first task on the taskQueue as a promise.
* Each task is a function returned by https://github.com/qunitjs/qunit/blob/master/src/test.js#L381
*/
function processTaskQueue( start ) {
if ( taskQueue.length && !config.blocking ) {
const elapsedTime = now() - start;

if ( !defined.setTimeout || config.updateRate <= 0 || elapsedTime < config.updateRate ) {
const task = taskQueue.shift();
task();
Promise.resolve( task() ).then( function() {
if ( !taskQueue.length ) {
advance();
} else {
processTaskQueue( start );
}
} );
} else {
setTimeout( advance );
break;
}
}

config.depth--;
}

/**
Expand Down
74 changes: 41 additions & 33 deletions src/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,34 +112,37 @@ Test.prototype = {
before: function() {
var i, startModule,
module = this.module,
promises = [],
notStartedModules = getNotStartedModules( module );

for ( i = notStartedModules.length - 1; i >= 0; i-- ) {
startModule = notStartedModules[ i ];
startModule.stats = { all: 0, bad: 0, started: now() };
emit( "suiteStart", startModule.suiteReport.start( true ) );
runLoggingCallbacks( "moduleStart", {
promises.push( runLoggingCallbacks( "moduleStart", {
name: startModule.name,
tests: startModule.tests
} );
} ) );
}

config.current = this;
return Promise.all( promises ).then( () => {
config.current = this;

this.testEnvironment = extend( {}, module.testEnvironment );
this.testEnvironment = extend( {}, module.testEnvironment );

this.started = now();
emit( "testStart", this.testReport.start( true ) );
runLoggingCallbacks( "testStart", {
name: this.testName,
module: module.name,
testId: this.testId,
previousFailure: this.previousFailure
this.started = now();
emit( "testStart", this.testReport.start( true ) );
return runLoggingCallbacks( "testStart", {
name: this.testName,
module: module.name,
testId: this.testId,
previousFailure: this.previousFailure
} );
} ).then( () => {
if ( !config.pollution ) {
saveGlobal();
}
} );

if ( !config.pollution ) {
saveGlobal();
}
},

run: function() {
Expand Down Expand Up @@ -313,7 +316,7 @@ Test.prototype = {
emit( "testEnd", this.testReport.end( true ) );
this.testReport.slimAssertions();

runLoggingCallbacks( "testDone", {
return runLoggingCallbacks( "testDone", {
name: testName,
module: moduleName,
skipped: skipped,
Expand All @@ -329,21 +332,26 @@ Test.prototype = {

// Source of Test
source: this.stack
} );

if ( module.testsRun === numberOfTests( module ) ) {
logSuiteEnd( module );

// Check if the parent modules, iteratively, are done. If that the case,
// we emit the `suiteEnd` event and trigger `moduleDone` callback.
let parent = module.parentModule;
while ( parent && parent.testsRun === numberOfTests( parent ) ) {
logSuiteEnd( parent );
parent = parent.parentModule;
} ).then( function() {
if ( module.testsRun === numberOfTests( module ) ) {
return logSuiteEnd( module );
}
}

config.current = undefined;
} ).then( function() {
if ( module.testsRun === numberOfTests( module ) ) {
const promises = [];

// Check if the parent modules, iteratively, are done. If that the case,
// we emit the `suiteEnd` event and trigger `moduleDone` callback.
let parent = module.parentModule;
while ( parent && parent.testsRun === numberOfTests( parent ) ) {
promises.push( logSuiteEnd( parent ) );
parent = parent.parentModule;
}
return Promise.all( promises );
}
} ).then( function() {
config.current = undefined;
} );

function logSuiteEnd( module ) {

Expand All @@ -352,7 +360,7 @@ Test.prototype = {
module.hooks = {};

emit( "suiteEnd", module.suiteReport.end( true ) );
runLoggingCallbacks( "moduleDone", {
return runLoggingCallbacks( "moduleDone", {
name: module.name,
tests: module.tests,
failed: module.stats.bad,
Expand Down Expand Up @@ -381,7 +389,7 @@ Test.prototype = {
function runTest() {
return [
function() {
test.before();
return test.before();
},

...test.hooks( "before" ),
Expand All @@ -404,7 +412,7 @@ Test.prototype = {
},

function() {
test.finish();
return test.finish();
}
];
}
Expand Down
14 changes: 14 additions & 0 deletions test/callbacks-promises.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>QUnit Callbacks Test Suite</title>
<link rel="stylesheet" href="../dist/qunit.css">
<script src="../dist/qunit.js"></script>
<script src="callbacks-promises.js"></script>
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
</body>
</html>
70 changes: 70 additions & 0 deletions test/callbacks-promises.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
var done = false;
var callbackCalled = {};

function timeoutPromiseCallback( callback, timeout ) {
return new Promise( function( resolve ) {
setTimeout( function() {
callback();
resolve();
}, timeout );
} );
}

QUnit.begin( function() {
return timeoutPromiseCallback( function() {
callbackCalled.begin = true;
}, 100 );
} );
QUnit.moduleStart( function() {
return timeoutPromiseCallback( function() {
callbackCalled.moduleStart = true;
}, 100 );
} );
QUnit.testStart( function() {
return timeoutPromiseCallback( function() {
callbackCalled.testStart = true;
}, 100 );
} );

QUnit.testDone( function() {
return timeoutPromiseCallback( function() {
callbackCalled.testStart = false;
callbackCalled.testDone = true;
}, 100 );
} );
QUnit.moduleDone( function() {
return timeoutPromiseCallback( function() {
callbackCalled.moduleStart = false;
callbackCalled.moduleDone = true;
}, 100 );
} );
QUnit.done( function() {
return timeoutPromiseCallback( function() {
callbackCalled.done = true;
}, 100 );
} );

QUnit.done( function() {
if ( done ) {
return;
}

done = true;

QUnit.test( "verify callback order", function( assert ) {
assert.ok( callbackCalled.begin );
assert.notOk( callbackCalled.moduleStart );
assert.notOk( callbackCalled.testStart );
assert.ok( callbackCalled.testDone );
assert.ok( callbackCalled.moduleDone );
assert.ok( callbackCalled.done );
} );
} );

QUnit.module( "module1", function() {
QUnit.test( "test1", function( assert ) {
assert.ok( callbackCalled.begin );
assert.ok( callbackCalled.moduleStart );
assert.ok( callbackCalled.testStart );
} );
} );

0 comments on commit 6711d27

Please sign in to comment.