diff --git a/Skeleton_modules/skeleton_mocha.js b/Skeleton_modules/skeleton_mocha.js index 8428a00..d575537 100644 --- a/Skeleton_modules/skeleton_mocha.js +++ b/Skeleton_modules/skeleton_mocha.js @@ -38,50 +38,70 @@ Skeleton.addModule('Mocha', function (batches) { var topicFn = context.topic, topic; if (topicFn !== undefined) { - // TODO: Handle async portion for 'this' (e.g. this.callback) - topic = topicFn.apply({}, topicChain); - topicChain.unshift(topic); + // If the item is not async, invoke the function and callback immediately + if (topicFn.SKELETON_ASYNC !== true) { + // Invoke the topic function + topic = topicFn.apply({}, topicChain); + + callback(topic); + } else { + // Otherwise, execute the topicFn in an async fashion + // Set up a callback for the item + var callback = function (topic) { + // Append the topic to the chain + topicChain.unshift(topic); + + // Run the next function + next(); + }; + topicFn.apply({'callback': callback}, topicChain); + } + } else { + // Otherwise, move on to the next parts + next(); } // Loop through the descriptions (skipping topic) - var description, - firstTopic = topicChain[0]; - for (description in context) { - if (description !== 'topic' && context.hasOwnProperty(description)) { - (function (description) { - var item = context[description], - itemType = typeof item; + function next() { + var description, + firstTopic = topicChain[0]; + for (description in context) { + if (description !== 'topic' && context.hasOwnProperty(description)) { + (function (description) { + var item = context[description], + itemType = typeof item; - // If the description is beforeEach, execute it as such - if (description === 'beforeEach') { - return beforeEach(item); - } else if (description === 'afterEach') { - return afterEach(item); - } + // If the description is beforeEach, execute it as such + if (description === 'beforeEach') { + return beforeEach(item); + } else if (description === 'afterEach') { + return afterEach(item); + } - // If the item is an object, it is a sub-context - if (itemType === 'object') { - // Describe and recurse the sub-context - describe(description, function () { - parseContext(item, topicChain); - }); - } else if (itemType === 'function') { - // Otherwise, if it is a function, it is a vow - // If the item is async, handle it as such - if (item.SKELETON_ASYNC === true) { - it(description, function (done) { - item.call({'callback': done}, firstTopic); - }); - } else { - // Otherwise, evaluate it normally - it(description, function () { - item(firstTopic); + // If the item is an object, it is a sub-context + if (itemType === 'object') { + // Describe and recurse the sub-context + describe(description, function () { + parseContext(item, topicChain); }); + } else if (itemType === 'function') { + // Otherwise, if it is a function, it is a vow + // If the item is async, handle it as such + if (item.SKELETON_ASYNC === true) { + it(description, function (done) { + item.call({'callback': done}, firstTopic); + }); + } else { + // Otherwise, evaluate it normally + it(description, function () { + item(firstTopic); + }); + } } - } - // Otherwise, it is a promise - // Mocha does not support promises - }(description)); + // Otherwise, it is a promise + // Mocha does not support promises + }(description)); + } } } } diff --git a/src-test/Skeleton_module.test.js b/src-test/Skeleton_module.test.js index fbd0835..30c184c 100644 --- a/src-test/Skeleton_module.test.js +++ b/src-test/Skeleton_module.test.js @@ -124,32 +124,37 @@ function testModule(moduleName, runner, finalCallback) { // TODO: Get this working - // test(moduleName + ' supports async topics', function () { - // var called = false, - // suite = new Skeleton; - - // suite.addBatch({ - // 'async': { - // topic: Skeleton.async(function () { - // var callback = this.callback; - // setTimeout(function () { - // called = true; - // callback(); - // }, 100); - // }), - // 'test1': function () { - // assert(called); - // } - // } - // }); - - // suite.exportTo(moduleName); - // runner(function () { - // assert(called); - // }); - // }); - - // TODO: Handle .async .beforeEach and .afterEach in helper method + testAsync(moduleName + ' supports async topics', function () { + var called = false, + suite = new Skeleton; + + suite.addBatch({ + 'async': { + topic: Skeleton.async(function () { + var callback = this.callback; + setTimeout(function () { + called = true; + callback(); + }, 100); + }), + 'test1': function () { + assert(called); + } + } + }); + + suite.exportTo(moduleName); + + var callback = this.callback; + runner(function () { + assert(called); + callback(); + }); + }, afterAsyncTopics); + + function afterAsyncTopics() { + + // TODO: Handle .async .beforeEach and .afterEach in helper method (.before -> test -> .after -- beware of race condition in async test and .after) testAsync(moduleName + ' supports async tests', function () { var called1 = false, @@ -182,26 +187,23 @@ function testModule(moduleName, runner, finalCallback) { // Assert that the tests are run in order (even when async) var callback = this.callback; runner(function () { - // Make sure that after sync has not been called in 10ms - setTimeout(function () { - assert(called2 === false); - }, 10); - - // But after the async test, everything is good + // Assert that called2 occurs after called1 setTimeout(function () { assert(called1); assert(called2); - + // Callback now that we are done callback(); }, 300); }); - }, next); - - function next() { + }, afterAsyncTests); + + function afterAsyncTests() { // Callback now that we are done finalCallback(); } + + } } // Expose testModule to the window scope diff --git a/src-test/Splat.js b/src-test/Splat.js index ca80948..add9ce9 100644 --- a/src-test/Splat.js +++ b/src-test/Splat.js @@ -38,12 +38,17 @@ var alert = window.alert || noop, Splat.log('TEST PASSED: ', name); }, 'testAsync': function (name, fn, callback) { - var asyncThis = { - 'callback': function () { - Splat.log('TEST PASSED: ', name); - callback(); - } - }; + var errTimeout = setTimeout(function () { + Splat.error('TEST TIMED OUT: ', name); + throw new Error('Test timed out: ' + name); + }, 2000), + asyncThis = { + 'callback': function () { + clearTimeout(errTimeout); + Splat.log('TEST PASSED: ', name); + callback(); + } + }; try { fn.call(asyncThis);