diff --git a/lib/reporters/base.js b/lib/reporters/base.js index 172d489785..f3a4e67ca3 100644 --- a/lib/reporters/base.js +++ b/lib/reporters/base.js @@ -302,7 +302,7 @@ function Base (runner) { failures.push(test); }); - runner.on('end', function () { + runner.once('end', function () { stats.end = new Date(); stats.duration = stats.end - stats.start; }); diff --git a/lib/reporters/dot.js b/lib/reporters/dot.js index 81e106edd0..3ccbce9ad3 100644 --- a/lib/reporters/dot.js +++ b/lib/reporters/dot.js @@ -56,7 +56,7 @@ function Dot (runner) { process.stdout.write(color('fail', Base.symbols.bang)); }); - runner.on('end', function () { + runner.once('end', function () { console.log(); self.epilogue(); }); diff --git a/lib/reporters/json-stream.js b/lib/reporters/json-stream.js index c0d79cf970..af3e86d259 100644 --- a/lib/reporters/json-stream.js +++ b/lib/reporters/json-stream.js @@ -39,7 +39,7 @@ function List (runner) { console.log(JSON.stringify(['fail', test])); }); - runner.on('end', function () { + runner.once('end', function () { process.stdout.write(JSON.stringify(['end', self.stats])); }); } diff --git a/lib/reporters/json.js b/lib/reporters/json.js index 259a782121..97989ccbb3 100644 --- a/lib/reporters/json.js +++ b/lib/reporters/json.js @@ -43,7 +43,7 @@ function JSONReporter (runner) { pending.push(test); }); - runner.on('end', function () { + runner.once('end', function () { var obj = { stats: self.stats, tests: tests.map(clean), diff --git a/lib/reporters/landing.js b/lib/reporters/landing.js index b8c7b5f20c..3cc036421d 100644 --- a/lib/reporters/landing.js +++ b/lib/reporters/landing.js @@ -81,7 +81,7 @@ function Landing (runner) { stream.write('\u001b[0m'); }); - runner.on('end', function () { + runner.once('end', function () { cursor.show(); console.log(); self.epilogue(); diff --git a/lib/reporters/list.js b/lib/reporters/list.js index a562cdb94c..719ec0166c 100644 --- a/lib/reporters/list.js +++ b/lib/reporters/list.js @@ -54,7 +54,7 @@ function List (runner) { console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); }); - runner.on('end', self.epilogue.bind(self)); + runner.once('end', self.epilogue.bind(self)); } /** diff --git a/lib/reporters/markdown.js b/lib/reporters/markdown.js index 9c06616ea9..2c27e1dc25 100644 --- a/lib/reporters/markdown.js +++ b/lib/reporters/markdown.js @@ -91,7 +91,7 @@ function Markdown (runner) { buf += '```\n\n'; }); - runner.on('end', function () { + runner.once('end', function () { process.stdout.write('# TOC\n'); process.stdout.write(generateTOC(runner.suite)); process.stdout.write(buf); diff --git a/lib/reporters/min.js b/lib/reporters/min.js index 0d772f9601..2573a43450 100644 --- a/lib/reporters/min.js +++ b/lib/reporters/min.js @@ -29,7 +29,7 @@ function Min (runner) { process.stdout.write('\u001b[1;3H'); }); - runner.on('end', this.epilogue.bind(this)); + runner.once('end', this.epilogue.bind(this)); } /** diff --git a/lib/reporters/nyan.js b/lib/reporters/nyan.js index 1be49a97b9..77478ebd51 100644 --- a/lib/reporters/nyan.js +++ b/lib/reporters/nyan.js @@ -52,7 +52,7 @@ function NyanCat (runner) { self.draw(); }); - runner.on('end', function () { + runner.once('end', function () { Base.cursor.show(); for (var i = 0; i < self.numberOfLines; i++) { write('\n'); diff --git a/lib/reporters/progress.js b/lib/reporters/progress.js index 9d545534bc..27b79f99e3 100644 --- a/lib/reporters/progress.js +++ b/lib/reporters/progress.js @@ -80,7 +80,7 @@ function Progress (runner, options) { // tests are complete, output some stats // and the failures if any - runner.on('end', function () { + runner.once('end', function () { cursor.show(); console.log(); self.epilogue(); diff --git a/lib/reporters/spec.js b/lib/reporters/spec.js index 993aff8dd3..d0543a5360 100644 --- a/lib/reporters/spec.js +++ b/lib/reporters/spec.js @@ -72,7 +72,7 @@ function Spec (runner) { console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); }); - runner.on('end', self.epilogue.bind(self)); + runner.once('end', self.epilogue.bind(self)); } /** diff --git a/lib/reporters/tap.js b/lib/reporters/tap.js index e37ac1b16f..4e99165f8f 100644 --- a/lib/reporters/tap.js +++ b/lib/reporters/tap.js @@ -51,7 +51,7 @@ function TAP (runner) { } }); - runner.on('end', function () { + runner.once('end', function () { console.log('# tests ' + (passes + failures)); console.log('# pass ' + passes); console.log('# fail ' + failures); diff --git a/lib/reporters/xunit.js b/lib/reporters/xunit.js index 7d98815ca2..faf96adac1 100644 --- a/lib/reporters/xunit.js +++ b/lib/reporters/xunit.js @@ -78,7 +78,7 @@ function XUnit (runner, options) { tests.push(test); }); - runner.on('end', function () { + runner.once('end', function () { self.write(tag('testsuite', { name: suiteName, tests: stats.tests, diff --git a/lib/runnable.js b/lib/runnable.js index e8ca41800f..1045b0680b 100644 --- a/lib/runnable.js +++ b/lib/runnable.js @@ -142,6 +142,24 @@ Runnable.prototype.isPending = function () { return this.pending || (this.parent && this.parent.isPending()); }; +/** + * Return `true` if this Runnable has failed. + * @return {boolean} + * @private + */ +Runnable.prototype.isFailed = function () { + return !this.isPending() && this.state === 'failed'; +}; + +/** + * Return `true` if this Runnable has passed. + * @return {boolean} + * @private + */ +Runnable.prototype.isPassed = function () { + return !this.isPending() && this.state === 'passed'; +}; + /** * Set or get number of retries. * diff --git a/lib/runner.js b/lib/runner.js index 2e74c985fe..5a7e3e03e0 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -726,21 +726,25 @@ Runner.prototype.uncaught = function (err) { runnable.clearTimeout(); - // Ignore errors if complete or pending - if (runnable.state || runnable.isPending()) { + // Ignore errors if already failed or pending + // See #3226 + if (runnable.isFailed() || runnable.isPending()) { return; } + // we cannot recover gracefully if a Runnable has already passed + // then fails asynchronously + var alreadyPassed = runnable.isPassed(); + // this will change the state to "failed" regardless of the current value this.fail(runnable, err); + if (!alreadyPassed) { + // recover from test + if (runnable.type === 'test') { + this.emit('test end', runnable); + this.hookUp('afterEach', this.next); + return; + } - // recover from test - if (runnable.type === 'test') { - this.emit('test end', runnable); - this.hookUp('afterEach', this.next); - return; - } - - // recover from hooks - if (runnable.type === 'hook') { + // recover from hooks var errSuite = this.suite; // if hook failure is in afterEach block if (runnable.fullTitle().indexOf('after each') > -1) { diff --git a/test/integration/fixtures/uncaught-fatal.fixture.js b/test/integration/fixtures/uncaught-fatal.fixture.js new file mode 100644 index 0000000000..10be283816 --- /dev/null +++ b/test/integration/fixtures/uncaught-fatal.fixture.js @@ -0,0 +1,11 @@ +'use strict'; + +it('should bail if a successful test asynchronously fails', function(done) { + done(); + process.nextTick(function () { + throw new Error('global error'); + }); +}); + +it('should not actually get run', function () { +}); diff --git a/test/integration/uncaught.spec.js b/test/integration/uncaught.spec.js index 9a3dadbbbd..db495a923a 100644 --- a/test/integration/uncaught.spec.js +++ b/test/integration/uncaught.spec.js @@ -40,4 +40,24 @@ describe('uncaught exceptions', function () { done(); }); }); + + it('handles uncaught exceptions from which Mocha cannot recover', function (done) { + run('uncaught-fatal.fixture.js', args, function (err, res) { + if (err) { + done(err); + return; + } + assert.equal(res.stats.pending, 0); + assert.equal(res.stats.passes, 1); + assert.equal(res.stats.failures, 1); + + assert.equal(res.failures[0].title, + 'should bail if a successful test asynchronously fails'); + assert.equal(res.passes[0].title, + 'should bail if a successful test asynchronously fails'); + + assert.equal(res.code, 1); + done(); + }); + }); }); diff --git a/test/reporters/doc.spec.js b/test/reporters/doc.spec.js index aadd826c0e..484b26fca3 100644 --- a/test/reporters/doc.spec.js +++ b/test/reporters/doc.spec.js @@ -6,9 +6,10 @@ var Doc = reporters.Doc; describe('Doc reporter', function () { var stdout; var stdoutWrite; - var runner = {}; + var runner; beforeEach(function () { stdout = []; + runner = {}; stdoutWrite = process.stdout.write; process.stdout.write = function (string) { stdout.push(string); @@ -24,7 +25,7 @@ describe('Doc reporter', function () { title: expectedTitle }; it('should log html with indents and expected title', function () { - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'suite') { callback(suite); } @@ -44,7 +45,7 @@ describe('Doc reporter', function () { title: unescapedTitle }; expectedTitle = '<div>' + expectedTitle + '</div>'; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'suite') { callback(suite); } @@ -64,7 +65,7 @@ describe('Doc reporter', function () { root: true }; it('should not log any html', function () { - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'suite') { callback(suite); } @@ -82,7 +83,7 @@ describe('Doc reporter', function () { root: false }; it('should log expected html with indents', function () { - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'suite end') { callback(suite); } @@ -100,7 +101,7 @@ describe('Doc reporter', function () { root: true }; it('should not log any html', function () { - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'suite end') { callback(suite); } @@ -123,7 +124,7 @@ describe('Doc reporter', function () { } }; it('should log html with indents and expected title and body', function () { - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pass') { callback(test); } @@ -144,7 +145,7 @@ describe('Doc reporter', function () { var expectedEscapedTitle = '<div>' + expectedTitle + '</div>'; var expectedEscapedBody = '<div>' + expectedBody + '</div>'; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pass') { callback(test); } @@ -171,7 +172,7 @@ describe('Doc reporter', function () { } }; it('should log html with indents and expected title, body and error', function () { - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'fail') { callback(test, expectedError); } @@ -195,7 +196,7 @@ describe('Doc reporter', function () { var expectedEscapedTitle = '<div>' + expectedTitle + '</div>'; var expectedEscapedBody = '<div>' + expectedBody + '</div>'; var expectedEscapedError = '<div>' + expectedError + '</div>'; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'fail') { callback(test, unescapedError); } diff --git a/test/reporters/dot.spec.js b/test/reporters/dot.spec.js index 8baccac453..47d3581723 100644 --- a/test/reporters/dot.spec.js +++ b/test/reporters/dot.spec.js @@ -31,7 +31,7 @@ describe('Dot reporter', function () { describe('on start', function () { it('should return a new line', function () { - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'start') { callback(); } @@ -50,7 +50,7 @@ describe('Dot reporter', function () { Base.window.width = 2; }); it('should return a new line and then a coma', function () { - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pending') { callback(); } @@ -66,7 +66,7 @@ describe('Dot reporter', function () { }); describe('if window width is equal to or less than 1', function () { it('should return a coma', function () { - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pending') { callback(); } @@ -91,7 +91,7 @@ describe('Dot reporter', function () { duration: 1, slow: function () { return 2; } }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pass') { callback(test); } @@ -113,7 +113,7 @@ describe('Dot reporter', function () { duration: 1, slow: function () { return 2; } }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pass') { callback(test); } @@ -132,7 +132,7 @@ describe('Dot reporter', function () { duration: 2, slow: function () { return 1; } }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pass') { callback(test); } @@ -158,7 +158,7 @@ describe('Dot reporter', function () { err: 'some error' } }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'fail') { callback(test); } @@ -179,7 +179,7 @@ describe('Dot reporter', function () { err: 'some error' } }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'fail') { callback(test); } @@ -195,7 +195,7 @@ describe('Dot reporter', function () { }); describe('on end', function () { it('should call the epilogue', function () { - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'end') { callback(); } diff --git a/test/reporters/json-stream.spec.js b/test/reporters/json-stream.spec.js index 049b3f6381..4ad6f65efb 100644 --- a/test/reporters/json-stream.spec.js +++ b/test/reporters/json-stream.spec.js @@ -19,7 +19,7 @@ describe('Json Stream reporter', function () { describe('on start', function () { it('should write stringified start with expected total', function () { - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'start') { callback(); } @@ -47,7 +47,7 @@ describe('Json Stream reporter', function () { currentRetry: function () { return currentRetry; }, slow: function () {} }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pass') { callback(expectedTest); } @@ -80,7 +80,7 @@ describe('Json Stream reporter', function () { message: expectedErrorMessage, stack: expectedErrorStack }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'fail') { callback(expectedTest, expectedError); } @@ -109,7 +109,7 @@ describe('Json Stream reporter', function () { var expectedError = { message: expectedErrorMessage }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'fail') { callback(expectedTest, expectedError); } @@ -125,7 +125,7 @@ describe('Json Stream reporter', function () { describe('on end', function () { it('should write end details', function () { - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'end') { callback(); } diff --git a/test/reporters/landing.spec.js b/test/reporters/landing.spec.js index 9a171e34e3..f055d15d6c 100644 --- a/test/reporters/landing.spec.js +++ b/test/reporters/landing.spec.js @@ -34,7 +34,7 @@ describe('Landing reporter', function () { it('should write new lines', function () { var cachedCursor = Base.cursor; Base.cursor.hide = function () {}; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'start') { callback(); } @@ -53,7 +53,7 @@ describe('Landing reporter', function () { Base.cursor.hide = function () { calledCursorHide = true; }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'start') { callback(); } @@ -73,7 +73,7 @@ describe('Landing reporter', function () { var test = { state: 'failed' }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'test end') { callback(test); } @@ -101,7 +101,7 @@ describe('Landing reporter', function () { var test = { state: 'success' }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'test end') { callback(test); } @@ -132,7 +132,7 @@ describe('Landing reporter', function () { Base.cursor.show = function () { calledCursorShow = true; }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'end') { callback(); } diff --git a/test/reporters/list.spec.js b/test/reporters/list.spec.js index 87978de011..ce862f5f2b 100644 --- a/test/reporters/list.spec.js +++ b/test/reporters/list.spec.js @@ -33,7 +33,7 @@ describe('List reporter', function () { return expectedTitle; } }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'start') { callback(); } @@ -61,7 +61,7 @@ describe('List reporter', function () { return expectedTitle; } }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pending') { callback(test); } @@ -89,7 +89,7 @@ describe('List reporter', function () { duration: expectedDuration, slow: function () {} }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pass') { callback(test); } @@ -117,7 +117,7 @@ describe('List reporter', function () { duration: expectedDuration, slow: function () {} }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pass') { callback(test); } @@ -148,7 +148,7 @@ describe('List reporter', function () { duration: expectedDuration, slow: function () {} }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'fail') { callback(test); } @@ -174,12 +174,12 @@ describe('List reporter', function () { duration: expectedDuration, slow: function () {} }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'fail') { callback(test); } }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'fail') { callback(test); } @@ -198,7 +198,7 @@ describe('List reporter', function () { var test = {}; var checked = false; var err; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (!checked && event === 'fail') { err = new Error('fake failure object with actual/expected'); err.actual = actual; @@ -219,7 +219,7 @@ describe('List reporter', function () { describe('on end', function () { it('should call epilogue', function () { var calledEpilogue = false; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'end') { callback(); } diff --git a/test/reporters/markdown.spec.js b/test/reporters/markdown.spec.js index 4971122ce3..51958e75f9 100644 --- a/test/reporters/markdown.spec.js +++ b/test/reporters/markdown.spec.js @@ -31,7 +31,7 @@ describe('Markdown reporter', function () { suites: [] }] }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'suite') { callback(expectedSuite); } @@ -76,7 +76,7 @@ describe('Markdown reporter', function () { slow: function () {}, body: expectedBody }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pass') { callback(expectedTest); } diff --git a/test/reporters/min.spec.js b/test/reporters/min.spec.js index e19ca0bec1..47e3211080 100644 --- a/test/reporters/min.spec.js +++ b/test/reporters/min.spec.js @@ -19,7 +19,7 @@ describe('Min reporter', function () { describe('on start', function () { it('should clear screen then set cursor position', function () { - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'start') { callback(); } @@ -38,7 +38,7 @@ describe('Min reporter', function () { describe('on end', function () { it('should call epilogue', function () { var calledEpilogue = false; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'end') { callback(); } diff --git a/test/reporters/nyan.spec.js b/test/reporters/nyan.spec.js index b90c3e3af4..9192f0ec14 100644 --- a/test/reporters/nyan.spec.js +++ b/test/reporters/nyan.spec.js @@ -22,7 +22,7 @@ describe('Nyan reporter', function () { describe('on start', function () { it('should call draw', function () { var calledDraw = false; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'start') { callback(); } @@ -41,7 +41,7 @@ describe('Nyan reporter', function () { describe('on pending', function () { it('should call draw', function () { var calledDraw = false; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pending') { callback(); } @@ -60,7 +60,7 @@ describe('Nyan reporter', function () { describe('on pass', function () { it('should call draw', function () { var calledDraw = false; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pass') { var test = { duration: '', @@ -83,7 +83,7 @@ describe('Nyan reporter', function () { describe('on fail', function () { it('should call draw', function () { var calledDraw = false; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'fail') { var test = { err: '' @@ -105,7 +105,7 @@ describe('Nyan reporter', function () { describe('on end', function () { it('should call epilogue', function () { var calledEpilogue = false; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'end') { callback(); } @@ -123,7 +123,7 @@ describe('Nyan reporter', function () { }); it('should write numberOfLines amount of new lines', function () { var expectedNumberOfLines = 4; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'end') { callback(); } @@ -145,7 +145,7 @@ describe('Nyan reporter', function () { Base.cursor.show = function () { showCalled = true; }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'end') { callback(); } @@ -177,7 +177,7 @@ describe('Nyan reporter', function () { describe('if tick is false', function () { it('should draw face with expected spaces, _ and ^', function () { - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); nyanCat.stats = { passes: 2, pending: 1, failures: 0 }; nyanCat.draw.call({ @@ -213,7 +213,7 @@ describe('Nyan reporter', function () { }); describe('if tick is true', function () { it('should draw face with expected spaces, _ and ~', function () { - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); nyanCat.stats = { passes: 2, pending: 1, failures: 0 }; nyanCat.draw.call({ @@ -262,7 +262,7 @@ describe('Nyan reporter', function () { }); it('should write cursor down interaction with expected number', function () { - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); var expectedNumber = 25; nyanCat.cursorDown(expectedNumber); @@ -287,7 +287,7 @@ describe('Nyan reporter', function () { }); it('should write cursor up interaction with expected number', function () { - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); var expectedNumber = 25; nyanCat.cursorUp(expectedNumber); @@ -313,7 +313,7 @@ describe('Nyan reporter', function () { }); it('should return argument string', function () { - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); var expectedString = 'hello'; var outputString = nyanCat.rainbowify(expectedString); @@ -334,7 +334,7 @@ describe('Nyan reporter', function () { it('should return rainbowified string from the given string and predefined codes', function () { var startCode = '\u001b[38;5;'; var endCode = '\u001b[0m'; - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); var expectedString = 'hello'; var colorCode = 'somecode'; var expectedRainbowifyString = startCode + colorCode + 'm' + expectedString + endCode; @@ -353,7 +353,7 @@ describe('Nyan reporter', function () { describe('appendRainbow', function () { describe('if tick is true', function () { it('should set an _ segment', function () { - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); var expectedSegment; var inputArray = []; var trajectories = [inputArray, inputArray, inputArray, inputArray]; @@ -370,7 +370,7 @@ describe('Nyan reporter', function () { expect(expectedSegment).to.equal('_'); }); it('should shift each trajectory item, if its length is greater of equal to its max width', function () { - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); var rainbowifyResult = 'rainbowify'; var inputArray = ['itemToShify']; @@ -390,7 +390,7 @@ describe('Nyan reporter', function () { }); describe('if tick is false', function () { it('should set an - segment', function () { - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); var expectedSegment; var inputArray = []; var trajectories = [inputArray, inputArray, inputArray, inputArray]; @@ -424,7 +424,7 @@ describe('Nyan reporter', function () { var passes = 2; var pending = 1; var failures = 1; - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); nyanCat.drawScoreboard.call({ cursorUp: function () {}, stats: { passes: passes, pending: pending, failures: failures }, @@ -455,7 +455,7 @@ describe('Nyan reporter', function () { var expectedCursorArgument = null; var expectedNumberOfLines = 1000; - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); nyanCat.drawScoreboard.call({ cursorUp: function (lines) { expectedCursorArgument = lines; @@ -481,7 +481,7 @@ describe('Nyan reporter', function () { var expectedContents = 'input'; var inputArray = [expectedContents]; var trajectories = [inputArray]; - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); nyanCat.drawRainbow.call({ cursorUp: function () {}, trajectories: trajectories, @@ -507,7 +507,7 @@ describe('Nyan reporter', function () { var expectedCursorArgument = null; var expectedNumberOfLines = 1000; - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); nyanCat.drawRainbow.call({ cursorUp: function (lines) { expectedCursorArgument = lines; @@ -523,25 +523,25 @@ describe('Nyan reporter', function () { }); describe('face', function () { it('expected face:(x .x) when "failures" at least one', function () { - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); nyanCat.stats = { passes: 2, pending: 1, failures: 1 }; expect(nyanCat.face()).to.equal('( x .x)'); }); it('expected face:(x .x) when "pending" at least one and no failing', function () { - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); nyanCat.stats = { passes: 2, pending: 1, failures: 0 }; expect(nyanCat.face()).to.equal('( o .o)'); }); it('expected face:(^ .^) when "passing" only', function () { - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); nyanCat.stats = { passes: 1, pending: 0, failures: 0 }; expect(nyanCat.face()).to.equal('( ^ .^)'); }); it('expected face:(- .-) when otherwise', function (done) { - var nyanCat = new NyanCat({on: function () {}}); + var nyanCat = new NyanCat({on: function () {}, once: function () {}}); nyanCat.stats = { passes: 0, pending: 0, failures: 0 }; expect(nyanCat.face()).to.equal('( - .-)'); done(); diff --git a/test/reporters/progress.spec.js b/test/reporters/progress.spec.js index 45ab2f42b8..02c4b723dd 100644 --- a/test/reporters/progress.spec.js +++ b/test/reporters/progress.spec.js @@ -25,7 +25,7 @@ describe('Progress reporter', function () { Base.cursor.hide = function () { calledCursorHide = true; }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'start') { callback(); } @@ -52,7 +52,7 @@ describe('Progress reporter', function () { var expectedTotal = 1; var expectedOptions = {}; runner.total = expectedTotal; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'test end') { callback(); } @@ -94,7 +94,7 @@ describe('Progress reporter', function () { reporterOptions: expectedOptions }; runner.total = expectedTotal; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'test end') { callback(); } @@ -126,7 +126,7 @@ describe('Progress reporter', function () { Base.cursor.show = function () { calledCursorShow = true; }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'end') { callback(); } diff --git a/test/reporters/spec.spec.js b/test/reporters/spec.spec.js index 70a68169ad..f3cfd6c220 100644 --- a/test/reporters/spec.spec.js +++ b/test/reporters/spec.spec.js @@ -31,7 +31,7 @@ describe('Spec reporter', function () { var suite = { title: expectedTitle }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'suite') { callback(suite); } @@ -50,7 +50,7 @@ describe('Spec reporter', function () { var suite = { title: expectedTitle }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pending') { callback(suite); } @@ -73,7 +73,7 @@ describe('Spec reporter', function () { duration: expectedDuration, slow: function () { return 1; } }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pass') { callback(test); } @@ -93,7 +93,7 @@ describe('Spec reporter', function () { duration: expectedDuration, slow: function () { return 2; } }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pass') { callback(test); } @@ -112,7 +112,7 @@ describe('Spec reporter', function () { var test = { title: expectedTitle }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'fail') { callback(test); } diff --git a/test/reporters/tap.spec.js b/test/reporters/tap.spec.js index 13ddc8e521..84a4875f46 100644 --- a/test/reporters/tap.spec.js +++ b/test/reporters/tap.spec.js @@ -22,7 +22,7 @@ describe('TAP reporter', function () { var expectedSuite = 'some suite'; var expectedTotal = 10; var expectedString; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'start') { callback(); } @@ -53,7 +53,7 @@ describe('TAP reporter', function () { return expectedTitle; } }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'test end') { callback(); } @@ -82,7 +82,7 @@ describe('TAP reporter', function () { }, slow: function () {} }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'test end') { callback(); } @@ -116,7 +116,7 @@ describe('TAP reporter', function () { var error = { stack: expectedStack }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'test end') { callback(); } @@ -148,7 +148,7 @@ describe('TAP reporter', function () { slow: function () {} }; var error = {}; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'test end') { callback(); } @@ -181,7 +181,7 @@ describe('TAP reporter', function () { }, slow: function () {} }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'fail') { callback(test, {}); } diff --git a/test/reporters/xunit.spec.js b/test/reporters/xunit.spec.js index 12021a11c8..916f3e650b 100644 --- a/test/reporters/xunit.spec.js +++ b/test/reporters/xunit.spec.js @@ -15,7 +15,8 @@ describe('XUnit reporter', function () { beforeEach(function () { stdout = []; runner = { - on: function () {} + on: function () {}, + once: function () {} }; }); @@ -75,7 +76,7 @@ describe('XUnit reporter', function () { name: 'pass', slow: function () {} }; - runner.on = function (event, callback) { + runner.on = runner.once = function (event, callback) { if (event === 'pending') { callback(pendingTest); } @@ -110,7 +111,7 @@ describe('XUnit reporter', function () { describe('done', function () { describe('if fileStream is truthly', function () { it('should run callback with failure inside streams end', function () { - var xunit = new XUnit({on: function () {}}); + var xunit = new XUnit({on: function () {}, once: function () {}}); var callbackArgument = null; var callback = function (failures) { callbackArgument = failures; @@ -135,7 +136,7 @@ describe('XUnit reporter', function () { }); describe('if fileStream is falsy', function () { it('should run callback with failure', function () { - var xunit = new XUnit({on: function () {}}); + var xunit = new XUnit({on: function () {}, once: function () {}}); var callbackArgument = null; var callback = function (failures) { callbackArgument = failures; @@ -156,7 +157,7 @@ describe('XUnit reporter', function () { describe('if fileStream is truthly', function () { it('should call fileStream write with line and new line', function () { var expectedWrite = null; - var xunit = new XUnit({on: function () {}}); + var xunit = new XUnit({on: function () {}, once: function () {}}); var fileStream = { write: function (write) { expectedWrite = write; @@ -178,7 +179,7 @@ describe('XUnit reporter', function () { stdout.push(string); }; - var xunit = new XUnit({on: function () {}}); + var xunit = new XUnit({on: function () {}, once: function () {}}); var expectedLine = 'some-line'; xunit.write.call( { fileStream: false }, @@ -199,7 +200,7 @@ describe('XUnit reporter', function () { stdout.push(string); }; - var xunit = new XUnit({on: function () {}}); + var xunit = new XUnit({on: function () {}, once: function () {}}); var expectedLine = 'some-line'; xunit.write.call( { fileStream: false }, @@ -216,7 +217,7 @@ describe('XUnit reporter', function () { describe('test', function () { describe('on test failure', function () { it('should write expected tag with error details', function () { - var xunit = new XUnit({on: function () {}}); + var xunit = new XUnit({on: function () {}, once: function () {}}); var expectedWrite = null; var expectedClassName = 'fullTitle'; @@ -253,7 +254,7 @@ describe('XUnit reporter', function () { }); describe('on test pending', function () { it('should write expected tag', function () { - var xunit = new XUnit({on: function () {}}); + var xunit = new XUnit({on: function () {}, once: function () {}}); var expectedClassName = 'fullTitle'; var expectedTitle = 'some title'; @@ -284,7 +285,7 @@ describe('XUnit reporter', function () { }); describe('on test in any other state', function () { it('should write expected tag', function () { - var xunit = new XUnit({on: function () {}}); + var xunit = new XUnit({on: function () {}, once: function () {}}); var expectedClassName = 'fullTitle'; var expectedTitle = 'some title'; @@ -337,6 +338,7 @@ describe('XUnit reporter', function () { events[eventName] = eventHandler; } }; + runner.once = runner.on; lines = []; fileStream = { diff --git a/test/unit/runnable.spec.js b/test/unit/runnable.spec.js index b7f2cecb7a..06545e10a2 100644 --- a/test/unit/runnable.spec.js +++ b/test/unit/runnable.spec.js @@ -490,4 +490,37 @@ describe('Runnable(title, fn)', function () { }); }); }); + + describe('#isFailed()', function () { + it('should return `true` if test has not failed', function () { + var test = new Runnable('foo', function () { + }); + // runner sets the state + test.run(function () { + expect(test.isFailed()).not.to.be.ok(); + }); + }); + + it('should return `true` if test has failed', function () { + var test = new Runnable('foo', function () { + }); + // runner sets the state + test.state = 'failed'; + test.run(function () { + expect(test.isFailed()).to.be.ok(); + }); + }); + + it('should return `false` if test is pending', function () { + var test = new Runnable('foo', function () { + }); + // runner sets the state + test.isPending = function () { + return true; + }; + test.run(function () { + expect(test.isFailed()).not.to.be.ok(); + }); + }); + }); });