From 8a6a4e2ea91b6a54335e79bbe6c24c63839349a6 Mon Sep 17 00:00:00 2001 From: "JeongHoon Byun (aka Outsider)" Date: Tue, 6 Nov 2018 07:23:15 +0900 Subject: [PATCH] Extract `runReporter` to capture output under tests (#3528) While refactoring the `dot` reporter test, we created a method for capturing output from running the reporter. It proved so handy at squelching test "noise" that JeongHoon extracted it and applied it to many of the other reporters. --- test/reporters/doc.spec.js | 42 ++++++----------- test/reporters/dot.spec.js | 51 ++++++--------------- test/reporters/helpers.js | 48 ++++++++++++++++++-- test/reporters/json-stream.spec.js | 37 ++++----------- test/reporters/landing.spec.js | 35 +++++--------- test/reporters/list.spec.js | 46 ++++++------------- test/reporters/markdown.spec.js | 22 +++------ test/reporters/min.spec.js | 25 ++++------ test/reporters/nyan.spec.js | 73 ++++++++++++++---------------- test/reporters/progress.spec.js | 18 ++++---- test/reporters/spec.spec.js | 28 ++++-------- test/reporters/tap.spec.js | 47 ++++++------------- 12 files changed, 186 insertions(+), 286 deletions(-) diff --git a/test/reporters/doc.spec.js b/test/reporters/doc.spec.js index e3de653528..857922b83e 100644 --- a/test/reporters/doc.spec.js +++ b/test/reporters/doc.spec.js @@ -4,22 +4,15 @@ var reporters = require('../../').reporters; var Doc = reporters.Doc; var createMockRunner = require('./helpers.js').createMockRunner; +var makeRunReporter = require('./helpers.js').createRunReporterFunction; describe('Doc reporter', function() { - var stdout; - var stdoutWrite; var runner; - beforeEach(function() { - stdout = []; - stdoutWrite = process.stdout.write; - process.stdout.write = function(string, enc, callback) { - stdout.push(string); - stdoutWrite.call(process.stdout, string, enc, callback); - }; - }); + var options = {}; + var runReporter = makeRunReporter(Doc); afterEach(function() { - process.stdout.write = stdoutWrite; + runner = undefined; }); describe('on suite', function() { @@ -32,8 +25,7 @@ describe('Doc reporter', function() { }; it('should log html with indents and expected title', function() { runner = createMockRunner('suite', 'suite', null, null, suite); - Doc.call(this, runner); - process.stdout.write = stdoutWrite; + var stdout = runReporter(this, runner, options); var expectedArray = [ '
\n', '

' + expectedTitle + '

\n', @@ -48,8 +40,7 @@ describe('Doc reporter', function() { }; expectedTitle = '<div>' + expectedTitle + '</div>'; runner = createMockRunner('suite', 'suite', null, null, suite); - Doc.call(this, runner); - process.stdout.write = stdoutWrite; + var stdout = runReporter(this, runner, options); var expectedArray = [ '
\n', '

' + expectedTitle + '

\n', @@ -64,8 +55,7 @@ describe('Doc reporter', function() { }; it('should not log any html', function() { runner = createMockRunner('suite', 'suite', null, null, suite); - Doc.call(this, runner); - process.stdout.write = stdoutWrite; + var stdout = runReporter(this, runner, options); expect(stdout, 'to be empty'); }); }); @@ -78,8 +68,7 @@ describe('Doc reporter', function() { }; it('should log expected html with indents', function() { runner = createMockRunner('suite end', 'suite end', null, null, suite); - Doc.call(this, runner); - process.stdout.write = stdoutWrite; + var stdout = runReporter(this, runner, options); var expectedArray = [' \n', '
\n']; expect(stdout, 'to equal', expectedArray); }); @@ -90,8 +79,7 @@ describe('Doc reporter', function() { }; it('should not log any html', function() { runner = createMockRunner('suite end', 'suite end', null, null, suite); - Doc.call(this, runner); - process.stdout.write = stdoutWrite; + var stdout = runReporter(this, runner, options); expect(stdout, 'to be empty'); }); }); @@ -109,8 +97,7 @@ describe('Doc reporter', function() { }; it('should log html with indents and expected title and body', function() { runner = createMockRunner('pass', 'pass', null, null, test); - Doc.call(this, runner); - process.stdout.write = stdoutWrite; + var stdout = runReporter(this, runner, options); var expectedArray = [ '
' + expectedTitle + '
\n', '
' + expectedBody + '
\n' @@ -128,8 +115,7 @@ describe('Doc reporter', function() { var expectedEscapedBody = '<div>' + expectedBody + '</div>'; runner = createMockRunner('pass', 'pass', null, null, test); - Doc.call(this, runner); - process.stdout.write = stdoutWrite; + var stdout = runReporter(this, runner, options); var expectedArray = [ '
' + expectedEscapedTitle + '
\n', '
' + expectedEscapedBody + '
\n' @@ -158,8 +144,7 @@ describe('Doc reporter', function() { test, expectedError ); - Doc.call(this, runner); - process.stdout.write = stdoutWrite; + var stdout = runReporter(this, runner, options); var expectedArray = [ '
' + expectedTitle + '
\n', '
' +
@@ -190,8 +175,7 @@ describe('Doc reporter', function() {
         test,
         unescapedError
       );
-      Doc.call(this, runner);
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter(this, runner, options);
       var expectedArray = [
         '    
' + expectedEscapedTitle + '
\n', '
' +
diff --git a/test/reporters/dot.spec.js b/test/reporters/dot.spec.js
index 0940d8be5f..472ec63d01 100644
--- a/test/reporters/dot.spec.js
+++ b/test/reporters/dot.spec.js
@@ -5,42 +5,17 @@ var Dot = reporters.Dot;
 var Base = reporters.Base;
 
 var createMockRunner = require('./helpers.js').createMockRunner;
+var makeRunReporter = require('./helpers.js').createRunReporterFunction;
 
 describe('Dot reporter', function() {
-  var stdout;
   var runner;
   var useColors;
   var windowWidth;
   var color;
-  var showOutput = false;
-
-  /**
-   * Run reporter using stream reassignment to capture output.
-   *
-   * @param {Object} stubSelf - Reporter-like stub instance
-   * @param {Runner} runner - Mock instance
-   * @param {boolean} [tee=false] - If `true`, echo captured output to screen
-   */
-  function runReporter(stubSelf, runner, tee) {
-    // Reassign stream in order to make a copy of all reporter output
-    var stdoutWrite = process.stdout.write;
-    process.stdout.write = function(string, enc, callback) {
-      stdout.push(string);
-      if (tee) {
-        stdoutWrite.call(process.stdout, string, enc, callback);
-      }
-    };
-
-    // Invoke reporter
-    Dot.call(stubSelf, runner);
-
-    // Revert stream reassignment here so reporter output
-    // can't be corrupted if any test assertions throw
-    process.stdout.write = stdoutWrite;
-  }
+  var options = {};
+  var runReporter = makeRunReporter(Dot);
 
   beforeEach(function() {
-    stdout = [];
     useColors = Base.useColors;
     windowWidth = Base.window.width;
     color = Base.color;
@@ -61,7 +36,7 @@ describe('Dot reporter', function() {
   describe('on start', function() {
     it('should write a newline', function() {
       runner = createMockRunner('start', 'start');
-      runReporter({epilogue: function() {}}, runner, showOutput);
+      var stdout = runReporter({epilogue: function() {}}, runner, options);
       var expectedArray = ['\n'];
       expect(stdout, 'to equal', expectedArray);
     });
@@ -73,7 +48,7 @@ describe('Dot reporter', function() {
       });
       it('should write a newline followed by a comma', function() {
         runner = createMockRunner('pending', 'pending');
-        runReporter({epilogue: function() {}}, runner, showOutput);
+        var stdout = runReporter({epilogue: function() {}}, runner, options);
         var expectedArray = ['\n  ', 'pending_' + Base.symbols.comma];
         expect(stdout, 'to equal', expectedArray);
       });
@@ -81,7 +56,7 @@ describe('Dot reporter', function() {
     describe('if window width is equal to or less than 1', function() {
       it('should write a comma', function() {
         runner = createMockRunner('pending', 'pending');
-        runReporter({epilogue: function() {}}, runner, showOutput);
+        var stdout = runReporter({epilogue: function() {}}, runner, options);
         var expectedArray = ['pending_' + Base.symbols.comma];
         expect(stdout, 'to equal', expectedArray);
       });
@@ -101,7 +76,7 @@ describe('Dot reporter', function() {
       describe('if test speed is fast', function() {
         it('should write a newline followed by a dot', function() {
           runner = createMockRunner('pass', 'pass', null, null, test);
-          runReporter({epilogue: function() {}}, runner, showOutput);
+          var stdout = runReporter({epilogue: function() {}}, runner, options);
           expect(test.speed, 'to equal', 'fast');
           var expectedArray = ['\n  ', 'fast_' + Base.symbols.dot];
           expect(stdout, 'to equal', expectedArray);
@@ -112,7 +87,7 @@ describe('Dot reporter', function() {
       describe('if test speed is fast', function() {
         it('should write a grey dot', function() {
           runner = createMockRunner('pass', 'pass', null, null, test);
-          runReporter({epilogue: function() {}}, runner, showOutput);
+          var stdout = runReporter({epilogue: function() {}}, runner, options);
           expect(test.speed, 'to equal', 'fast');
           var expectedArray = ['fast_' + Base.symbols.dot];
           expect(stdout, 'to equal', expectedArray);
@@ -122,7 +97,7 @@ describe('Dot reporter', function() {
         it('should write a yellow dot', function() {
           test.duration = 2;
           runner = createMockRunner('pass', 'pass', null, null, test);
-          runReporter({epilogue: function() {}}, runner, showOutput);
+          var stdout = runReporter({epilogue: function() {}}, runner, options);
           expect(test.speed, 'to equal', 'medium');
           var expectedArray = ['medium_' + Base.symbols.dot];
           expect(stdout, 'to equal', expectedArray);
@@ -132,7 +107,7 @@ describe('Dot reporter', function() {
         it('should write a bright yellow dot', function() {
           test.duration = 3;
           runner = createMockRunner('pass', 'pass', null, null, test);
-          runReporter({epilogue: function() {}}, runner, showOutput);
+          var stdout = runReporter({epilogue: function() {}}, runner, options);
           expect(test.speed, 'to equal', 'slow');
           var expectedArray = ['bright-yellow_' + Base.symbols.dot];
           expect(stdout, 'to equal', expectedArray);
@@ -152,7 +127,7 @@ describe('Dot reporter', function() {
       });
       it('should write a newline followed by an exclamation mark', function() {
         runner = createMockRunner('fail', 'fail', null, null, test);
-        runReporter({epilogue: function() {}}, runner, showOutput);
+        var stdout = runReporter({epilogue: function() {}}, runner, options);
         var expectedArray = ['\n  ', 'fail_' + Base.symbols.bang];
         expect(stdout, 'to equal', expectedArray);
       });
@@ -160,7 +135,7 @@ describe('Dot reporter', function() {
     describe('if window width is equal to or less than 1', function() {
       it('should write an exclamation mark', function() {
         runner = createMockRunner('fail', 'fail', null, null, test);
-        runReporter({epilogue: function() {}}, runner, showOutput);
+        var stdout = runReporter({epilogue: function() {}}, runner, options);
         var expectedArray = ['fail_' + Base.symbols.bang];
         expect(stdout, 'to equal', expectedArray);
       });
@@ -173,7 +148,7 @@ describe('Dot reporter', function() {
       var epilogue = function() {
         epilogueCalled = true;
       };
-      runReporter({epilogue: epilogue}, runner, showOutput);
+      runReporter({epilogue: epilogue}, runner, options);
       expect(epilogueCalled, 'to be', true);
     });
   });
diff --git a/test/reporters/helpers.js b/test/reporters/helpers.js
index e0c6604216..4da36fa600 100644
--- a/test/reporters/helpers.js
+++ b/test/reporters/helpers.js
@@ -155,9 +155,51 @@ function makeExpectedTest(
   };
 }
 
+/**
+ * Creates closure with reference to the reporter class constructor.
+ *
+ * @param {Function} ctor - Reporter class constructor
+ * @return {createRunReporterFunction~runReporter}
+ */
+function createRunReporterFunction(ctor) {
+  /**
+   * Run reporter using stream reassignment to capture output.
+   *
+   * @param {Object} stubSelf - Reporter-like stub instance
+   * @param {Runner} runner - Mock instance
+   * @param {Object} [options] - Reporter configuration settings
+   * @param {boolean} [tee=false] - Whether to echo output to screen
+   * @return {string[]} Lines of output written to `stdout`
+   */
+  var runReporter = function(stubSelf, runner, options, tee) {
+    var stdout = [];
+
+    // Reassign stream in order to make a copy of all reporter output
+    var stdoutWrite = process.stdout.write;
+    process.stdout.write = function(string, enc, callback) {
+      stdout.push(string);
+      if (tee) {
+        stdoutWrite.call(process.stdout, string, enc, callback);
+      }
+    };
+
+    // Invoke reporter
+    ctor.call(stubSelf, runner, options);
+
+    // Revert stream reassignment here so reporter output
+    // can't be corrupted if any test assertions throw
+    process.stdout.write = stdoutWrite;
+
+    return stdout;
+  };
+
+  return runReporter;
+}
+
 module.exports = {
-  createMockRunner: createMockRunner,
-  makeTest: makeTest,
   createElements: createElements,
-  makeExpectedTest: makeExpectedTest
+  createMockRunner: createMockRunner,
+  createRunReporterFunction: createRunReporterFunction,
+  makeExpectedTest: makeExpectedTest,
+  makeTest: makeTest
 };
diff --git a/test/reporters/json-stream.spec.js b/test/reporters/json-stream.spec.js
index 3c5e1831f2..8c9fcfff35 100644
--- a/test/reporters/json-stream.spec.js
+++ b/test/reporters/json-stream.spec.js
@@ -5,12 +5,12 @@ var JSONStream = reporters.JSONStream;
 
 var createMockRunner = require('./helpers').createMockRunner;
 var makeExpectedTest = require('./helpers').makeExpectedTest;
+var makeRunReporter = require('./helpers.js').createRunReporterFunction;
 
-describe('Json Stream reporter', function() {
+describe('JSON Stream reporter', function() {
   var runner;
-  var stdout;
-  var stdoutWrite;
-
+  var options = {};
+  var runReporter = makeRunReporter(JSONStream);
   var expectedTitle = 'some title';
   var expectedFullTitle = 'full title';
   var expectedDuration = 1000;
@@ -27,17 +27,8 @@ describe('Json Stream reporter', function() {
     message: expectedErrorMessage
   };
 
-  beforeEach(function() {
-    stdout = [];
-    stdoutWrite = process.stdout.write;
-    process.stdout.write = function(string, enc, callback) {
-      stdout.push(string);
-      stdoutWrite.call(process.stdout, string, enc, callback);
-    };
-  });
-
   afterEach(function() {
-    process.stdout.write = stdoutWrite;
+    runner = undefined;
   });
 
   describe('on start', function() {
@@ -45,9 +36,7 @@ describe('Json Stream reporter', function() {
       runner = createMockRunner('start', 'start');
       var expectedTotal = 12;
       runner.total = expectedTotal;
-      JSONStream.call({}, runner);
-
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter({}, runner, options);
 
       expect(
         stdout[0],
@@ -60,9 +49,7 @@ describe('Json Stream reporter', function() {
   describe('on pass', function() {
     it('should write stringified test data', function() {
       runner = createMockRunner('pass', 'pass', null, null, expectedTest);
-      JSONStream.call({}, runner);
-
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter({}, runner, options);
 
       expect(
         stdout[0],
@@ -93,9 +80,7 @@ describe('Json Stream reporter', function() {
           expectedError
         );
 
-        JSONStream.call({}, runner);
-
-        process.stdout.write = stdoutWrite;
+        var stdout = runReporter({}, runner, options);
 
         expect(
           stdout[0],
@@ -129,8 +114,7 @@ describe('Json Stream reporter', function() {
           expectedError
         );
 
-        JSONStream.call({}, runner);
-        process.stdout.write = stdoutWrite;
+        var stdout = runReporter(this, runner, options);
 
         expect(
           stdout[0],
@@ -154,8 +138,7 @@ describe('Json Stream reporter', function() {
   describe('on end', function() {
     it('should write end details', function() {
       runner = createMockRunner('end', 'end');
-      JSONStream.call({}, runner);
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter(this, runner, options);
       expect(stdout[0], 'to match', /end/);
     });
   });
diff --git a/test/reporters/landing.spec.js b/test/reporters/landing.spec.js
index da4134ce70..1fee291e41 100644
--- a/test/reporters/landing.spec.js
+++ b/test/reporters/landing.spec.js
@@ -5,11 +5,12 @@ var Landing = reporters.Landing;
 var Base = reporters.Base;
 
 var createMockRunner = require('./helpers').createMockRunner;
+var makeRunReporter = require('./helpers.js').createRunReporterFunction;
 
 describe('Landing reporter', function() {
-  var stdout;
-  var stdoutWrite;
   var runner;
+  var options = {};
+  var runReporter = makeRunReporter(Landing);
   var useColors;
   var windowWidth;
   var resetCode = '\u001b[0m';
@@ -25,12 +26,6 @@ describe('Landing reporter', function() {
   ];
 
   beforeEach(function() {
-    stdout = [];
-    stdoutWrite = process.stdout.write;
-    process.stdout.write = function(string, enc, callback) {
-      stdout.push(string);
-      stdoutWrite.call(process.stdout, string, enc, callback);
-    };
     useColors = Base.useColors;
     Base.useColors = false;
     windowWidth = Base.window.width;
@@ -40,7 +35,7 @@ describe('Landing reporter', function() {
   afterEach(function() {
     Base.useColors = useColors;
     Base.window.width = windowWidth;
-    process.stdout.write = stdoutWrite;
+    runner = undefined;
   });
 
   describe('on start', function() {
@@ -48,9 +43,7 @@ describe('Landing reporter', function() {
       var cachedCursor = Base.cursor;
       Base.cursor.hide = function() {};
       runner = createMockRunner('start', 'start');
-      Landing.call({}, runner);
-
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter({}, runner, options);
 
       expect(stdout[0], 'to equal', '\n\n\n  ');
       Base.cursor = cachedCursor;
@@ -63,9 +56,7 @@ describe('Landing reporter', function() {
         calledCursorHide = true;
       };
       runner = createMockRunner('start', 'start');
-      Landing.call({}, runner);
-
-      process.stdout.write = stdoutWrite;
+      runReporter({}, runner, options);
       expect(calledCursorHide, 'to be', true);
 
       Base.cursor = cachedCursor;
@@ -80,9 +71,7 @@ describe('Landing reporter', function() {
         };
         runner = createMockRunner('test end', 'test end', null, null, test);
         runner.total = 12;
-        Landing.call({}, runner);
-
-        process.stdout.write = stdoutWrite;
+        var stdout = runReporter({}, runner, options);
 
         expect(stdout, 'to equal', expectedArray);
       });
@@ -94,9 +83,7 @@ describe('Landing reporter', function() {
         };
         runner = createMockRunner('test end', 'test end', null, null, test);
 
-        Landing.call({}, runner);
-
-        process.stdout.write = stdoutWrite;
+        var stdout = runReporter({}, runner, options);
 
         expect(stdout, 'to equal', expectedArray);
       });
@@ -112,16 +99,16 @@ describe('Landing reporter', function() {
       runner = createMockRunner('end', 'end');
 
       var calledEpilogue = false;
-      Landing.call(
+      runReporter(
         {
           epilogue: function() {
             calledEpilogue = true;
           }
         },
-        runner
+        runner,
+        options
       );
 
-      process.stdout.write = stdoutWrite;
       expect(calledEpilogue, 'to be', true);
       expect(calledCursorShow, 'to be', true);
 
diff --git a/test/reporters/list.spec.js b/test/reporters/list.spec.js
index 7b9c74fb43..78895796c4 100644
--- a/test/reporters/list.spec.js
+++ b/test/reporters/list.spec.js
@@ -5,11 +5,12 @@ var List = reporters.List;
 var Base = reporters.Base;
 
 var createMockRunner = require('./helpers').createMockRunner;
+var makeRunReporter = require('./helpers.js').createRunReporterFunction;
 
 describe('List reporter', function() {
-  var stdout;
-  var stdoutWrite;
   var runner;
+  var options = {};
+  var runReporter = makeRunReporter(List);
   var useColors;
   var expectedTitle = 'some title';
   var expectedDuration = 100;
@@ -21,27 +22,20 @@ describe('List reporter', function() {
     slow: function() {}
   };
   beforeEach(function() {
-    stdout = [];
-    stdoutWrite = process.stdout.write;
-    process.stdout.write = function(string, enc, callback) {
-      stdout.push(string);
-      stdoutWrite.call(process.stdout, string, enc, callback);
-    };
     useColors = Base.useColors;
     Base.useColors = false;
   });
 
   afterEach(function() {
     Base.useColors = useColors;
-    process.stdout.write = stdoutWrite;
+    runner = undefined;
   });
 
   describe('on start and test', function() {
     it('should write expected new line and title to the console', function() {
       runner = createMockRunner('start test', 'start', 'test', null, test);
-      List.call({epilogue: function() {}}, runner);
+      var stdout = runReporter({epilogue: function() {}}, runner, options);
 
-      process.stdout.write = stdoutWrite;
       var startString = '\n';
       var testString = '    ' + expectedTitle + ': ';
       var expectedArray = [startString, testString];
@@ -51,9 +45,7 @@ describe('List reporter', function() {
   describe('on pending', function() {
     it('should write expected title to the console', function() {
       runner = createMockRunner('pending test', 'pending', null, null, test);
-      List.call({epilogue: function() {}}, runner);
-
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter({epilogue: function() {}}, runner, options);
 
       expect(stdout[0], 'to equal', '  - ' + expectedTitle + '\n');
     });
@@ -66,9 +58,7 @@ describe('List reporter', function() {
         calledCursorCR = true;
       };
       runner = createMockRunner('pass', 'pass', null, null, test);
-      List.call({epilogue: function() {}}, runner);
-
-      process.stdout.write = stdoutWrite;
+      runReporter({epilogue: function() {}}, runner, options);
 
       expect(calledCursorCR, 'to be', true);
 
@@ -81,9 +71,7 @@ describe('List reporter', function() {
       var cachedCursor = Base.cursor;
       Base.cursor.CR = function() {};
       runner = createMockRunner('pass', 'pass', null, null, test);
-      List.call({epilogue: function() {}}, runner);
-
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter({epilogue: function() {}}, runner, options);
 
       expect(
         stdout[0],
@@ -109,9 +97,7 @@ describe('List reporter', function() {
         calledCursorCR = true;
       };
       runner = createMockRunner('fail', 'fail', null, null, test);
-      List.call({epilogue: function() {}}, runner);
-
-      process.stdout.write = stdoutWrite;
+      runReporter({epilogue: function() {}}, runner, options);
 
       expect(calledCursorCR, 'to be', true);
 
@@ -122,9 +108,7 @@ describe('List reporter', function() {
       var expectedErrorCount = 1;
       Base.cursor.CR = function() {};
       runner = createMockRunner('fail', 'fail', null, null, test);
-      List.call({epilogue: function() {}}, runner);
-
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter({epilogue: function() {}}, runner, options);
 
       expect(
         stdout[0],
@@ -140,6 +124,7 @@ describe('List reporter', function() {
       var checked = false;
       var err;
       test = {};
+      runner = createMockRunner('fail', 'fail', null, null, test);
       runner.on = runner.once = function(event, callback) {
         if (!checked && event === 'fail') {
           err = new Error('fake failure object with actual/expected');
@@ -150,9 +135,8 @@ describe('List reporter', function() {
           checked = true;
         }
       };
-      List.call({epilogue: function() {}}, runner);
+      runReporter({epilogue: function() {}}, runner, options);
 
-      process.stdout.write = stdoutWrite;
       expect(typeof err.actual, 'to be', 'string');
       expect(typeof err.expected, 'to be', 'string');
     });
@@ -162,15 +146,15 @@ describe('List reporter', function() {
     it('should call epilogue', function() {
       var calledEpilogue = false;
       runner = createMockRunner('end', 'end');
-      List.call(
+      runReporter(
         {
           epilogue: function() {
             calledEpilogue = true;
           }
         },
-        runner
+        runner,
+        options
       );
-      process.stdout.write = stdoutWrite;
 
       expect(calledEpilogue, 'to be', true);
     });
diff --git a/test/reporters/markdown.spec.js b/test/reporters/markdown.spec.js
index f6fc63f119..842d7c7643 100644
--- a/test/reporters/markdown.spec.js
+++ b/test/reporters/markdown.spec.js
@@ -4,26 +4,18 @@ var reporters = require('../../').reporters;
 var Markdown = reporters.Markdown;
 
 var createMockRunner = require('./helpers').createMockRunner;
+var makeRunReporter = require('./helpers.js').createRunReporterFunction;
 
 describe('Markdown reporter', function() {
-  var stdout;
-  var stdoutWrite;
   var runner;
+  var options = {};
+  var runReporter = makeRunReporter(Markdown);
   var expectedTitle = 'expected title';
   var expectedFullTitle = 'full title';
   var sluggedFullTitle = 'full-title';
 
-  beforeEach(function() {
-    stdout = [];
-    stdoutWrite = process.stdout.write;
-    process.stdout.write = function(string, enc, callback) {
-      stdout.push(string);
-      stdoutWrite.call(process.stdout, string, enc, callback);
-    };
-  });
-
   afterEach(function() {
-    process.stdout.write = stdoutWrite;
+    runner = undefined;
   });
 
   describe("on 'suite'", function() {
@@ -51,8 +43,7 @@ describe('Markdown reporter', function() {
         expectedSuite
       );
       runner.suite = expectedSuite;
-      Markdown.call({}, runner);
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter({}, runner, options);
 
       var expectedArray = [
         '# TOC\n',
@@ -97,8 +88,7 @@ describe('Markdown reporter', function() {
       };
       runner = createMockRunner('pass end', 'pass', 'end', null, expectedTest);
       runner.suite = expectedSuite;
-      Markdown.call({}, runner);
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter({}, runner, options);
 
       var expectedArray = [
         '# TOC\n',
diff --git a/test/reporters/min.spec.js b/test/reporters/min.spec.js
index 30b05126ec..f88adf31d7 100644
--- a/test/reporters/min.spec.js
+++ b/test/reporters/min.spec.js
@@ -4,31 +4,22 @@ var reporters = require('../../').reporters;
 var Min = reporters.Min;
 
 var createMockRunner = require('./helpers').createMockRunner;
+var makeRunReporter = require('./helpers.js').createRunReporterFunction;
 
 describe('Min reporter', function() {
-  var stdout;
-  var stdoutWrite;
   var runner;
-
-  beforeEach(function() {
-    stdout = [];
-    stdoutWrite = process.stdout.write;
-    process.stdout.write = function(string, enc, callback) {
-      stdout.push(string);
-      stdoutWrite.call(process.stdout, string, enc, callback);
-    };
-  });
+  var options = {};
+  var runReporter = makeRunReporter(Min);
 
   afterEach(function() {
-    process.stdout.write = stdoutWrite;
+    runner = undefined;
   });
 
   describe('on start', function() {
     it('should clear screen then set cursor position', function() {
       runner = createMockRunner('start', 'start');
-      Min.call({epilogue: function() {}}, runner);
+      var stdout = runReporter({epilogue: function() {}}, runner, options);
 
-      process.stdout.write = stdoutWrite;
       var expectedArray = ['\u001b[2J', '\u001b[1;3H'];
       expect(stdout, 'to equal', expectedArray);
     });
@@ -38,15 +29,15 @@ describe('Min reporter', function() {
     it('should call epilogue', function() {
       var calledEpilogue = false;
       runner = createMockRunner('end', 'end');
-      Min.call(
+      runReporter(
         {
           epilogue: function() {
             calledEpilogue = true;
           }
         },
-        runner
+        runner,
+        options
       );
-      process.stdout.write = stdoutWrite;
 
       expect(calledEpilogue, 'to be', true);
     });
diff --git a/test/reporters/nyan.spec.js b/test/reporters/nyan.spec.js
index 1296ab1195..96bbda6766 100644
--- a/test/reporters/nyan.spec.js
+++ b/test/reporters/nyan.spec.js
@@ -5,41 +5,33 @@ var NyanCat = reporters.Nyan;
 var Base = reporters.Base;
 
 var createMockRunner = require('./helpers').createMockRunner;
+var makeRunReporter = require('./helpers.js').createRunReporterFunction;
 
 describe('Nyan reporter', function() {
   describe('events', function() {
     var runner;
-    var stdout;
-    var stdoutWrite;
     var calledDraw;
-
-    beforeEach(function() {
-      stdout = [];
-      stdoutWrite = process.stdout.write;
-      process.stdout.write = function(string, enc, callback) {
-        stdout.push(string);
-        stdoutWrite.call(process.stdout, string, enc, callback);
-      };
-    });
+    var options = {};
+    var runReporter = makeRunReporter(NyanCat);
 
     afterEach(function() {
-      process.stdout.write = stdoutWrite;
+      runner = undefined;
     });
 
     describe('on start', function() {
       it('should call draw', function() {
         calledDraw = false;
         runner = createMockRunner('start', 'start');
-        NyanCat.call(
+        runReporter(
           {
             draw: function() {
               calledDraw = true;
             },
             generateColors: function() {}
           },
-          runner
+          runner,
+          options
         );
-        process.stdout.write = stdoutWrite;
 
         expect(calledDraw, 'to be', true);
       });
@@ -48,16 +40,16 @@ describe('Nyan reporter', function() {
       it('should call draw', function() {
         calledDraw = false;
         runner = createMockRunner('pending', 'pending');
-        NyanCat.call(
+        runReporter(
           {
             draw: function() {
               calledDraw = true;
             },
             generateColors: function() {}
           },
-          runner
+          runner,
+          options
         );
-        process.stdout.write = stdoutWrite;
 
         expect(calledDraw, 'to be', true);
       });
@@ -70,16 +62,16 @@ describe('Nyan reporter', function() {
           slow: function() {}
         };
         runner = createMockRunner('pass', 'pass', null, null, test);
-        NyanCat.call(
+        runReporter(
           {
             draw: function() {
               calledDraw = true;
             },
             generateColors: function() {}
           },
-          runner
+          runner,
+          options
         );
-        process.stdout.write = stdoutWrite;
 
         expect(calledDraw, 'to be', true);
       });
@@ -91,16 +83,16 @@ describe('Nyan reporter', function() {
           err: ''
         };
         runner = createMockRunner('fail', 'fail', null, null, test);
-        NyanCat.call(
+        runReporter(
           {
             draw: function() {
               calledDraw = true;
             },
             generateColors: function() {}
           },
-          runner
+          runner,
+          options
         );
-        process.stdout.write = stdoutWrite;
 
         expect(calledDraw, 'to be', true);
       });
@@ -109,7 +101,7 @@ describe('Nyan reporter', function() {
       it('should call epilogue', function() {
         var calledEpilogue = false;
         runner = createMockRunner('end', 'end');
-        NyanCat.call(
+        runReporter(
           {
             draw: function() {},
             generateColors: function() {},
@@ -117,28 +109,28 @@ describe('Nyan reporter', function() {
               calledEpilogue = true;
             }
           },
-          runner
+          runner,
+          options
         );
-        process.stdout.write = stdoutWrite;
 
         expect(calledEpilogue, 'to be', true);
       });
       it('should write numberOfLines amount of new lines', function() {
         var expectedNumberOfLines = 4;
         runner = createMockRunner('end', 'end');
-        NyanCat.call(
+        var stdout = runReporter(
           {
             draw: function() {},
             generateColors: function() {},
             epilogue: function() {}
           },
-          runner
+          runner,
+          options
         );
 
         var arrayOfNewlines = stdout.filter(function(value) {
           return value === '\n';
         });
-        process.stdout.write = stdoutWrite;
 
         expect(arrayOfNewlines, 'to have length', expectedNumberOfLines);
       });
@@ -149,16 +141,16 @@ describe('Nyan reporter', function() {
           showCalled = true;
         };
         runner = createMockRunner('end', 'end');
-        NyanCat.call(
+        runReporter(
           {
             draw: function() {},
             generateColors: function() {},
             epilogue: function() {}
           },
-          runner
+          runner,
+          options
         );
 
-        process.stdout.write = stdoutWrite;
         expect(showCalled, 'to be', true);
         Base.cursor.show = cachedShow;
       });
@@ -199,7 +191,6 @@ describe('Nyan reporter', function() {
           cursorUp: function() {}
         });
 
-        process.stdout.write = stdoutWrite;
         var expectedArray = [
           '\u001b[0C',
           '_,------,',
@@ -235,7 +226,6 @@ describe('Nyan reporter', function() {
           cursorUp: function() {}
         });
 
-        // process.stdout.write = stdoutWrite;
         var expectedArray = [
           '\u001b[0C',
           '_,------,',
@@ -276,7 +266,6 @@ describe('Nyan reporter', function() {
       var expectedNumber = 25;
 
       nyanCat.cursorDown(expectedNumber);
-      process.stdout.write = stdoutWrite;
       var expectedArray = ['\u001b[' + expectedNumber + 'B'];
       expect(stdout, 'to equal', expectedArray);
     });
@@ -303,7 +292,6 @@ describe('Nyan reporter', function() {
       var expectedNumber = 25;
 
       nyanCat.cursorUp(expectedNumber);
-      process.stdout.write = stdoutWrite;
       var expectedArray = ['\u001b[' + expectedNumber + 'A'];
       expect(stdout, 'to equal', expectedArray);
     });
@@ -432,13 +420,16 @@ describe('Nyan reporter', function() {
     var stdoutWrite;
     var stdout;
     var cachedColor;
+    var showOutput = false;
 
     beforeEach(function() {
       stdout = [];
       stdoutWrite = process.stdout.write;
       process.stdout.write = function(string, enc, callback) {
         stdout.push(string);
-        stdoutWrite.call(process.stdout, string, enc, callback);
+        if (showOutput) {
+          stdoutWrite.call(process.stdout, string, enc, callback);
+        }
       };
       cachedColor = Base.color;
       Base.color = function(type, n) {
@@ -496,13 +487,16 @@ describe('Nyan reporter', function() {
   describe('drawRainbow', function() {
     var stdoutWrite;
     var stdout;
+    var showOutput = false;
 
     beforeEach(function() {
       stdout = [];
       stdoutWrite = process.stdout.write;
       process.stdout.write = function(string, enc, callback) {
         stdout.push(string);
-        stdoutWrite.call(process.stdout, string, enc, callback);
+        if (showOutput) {
+          stdoutWrite.call(process.stdout, string, enc, callback);
+        }
       };
     });
 
@@ -524,7 +518,6 @@ describe('Nyan reporter', function() {
         numberOfLines: 1
       });
 
-      process.stdout.write = stdoutWrite;
       var expectedArray = [
         '\u001b[' + expectedWidth + 'C',
         expectedContents,
diff --git a/test/reporters/progress.spec.js b/test/reporters/progress.spec.js
index ef08ea5582..f19bb3988d 100644
--- a/test/reporters/progress.spec.js
+++ b/test/reporters/progress.spec.js
@@ -5,11 +5,13 @@ var Progress = reporters.Progress;
 var Base = reporters.Base;
 
 var createMockRunner = require('./helpers').createMockRunner;
+var makeRunReporter = require('./helpers.js').createRunReporterFunction;
 
 describe('Progress reporter', function() {
   var stdout;
   var stdoutWrite;
   var runner;
+  var runReporter = makeRunReporter(Progress);
 
   beforeEach(function() {
     stdout = [];
@@ -32,9 +34,8 @@ describe('Progress reporter', function() {
         calledCursorHide = true;
       };
       runner = createMockRunner('start', 'start');
-      Progress.call({}, runner);
+      runReporter({}, runner, {});
 
-      process.stdout.write = stdoutWrite;
       expect(calledCursorHide, 'to be', true);
 
       Base.cursor = cachedCursor;
@@ -55,9 +56,7 @@ describe('Progress reporter', function() {
         var expectedOptions = {};
         runner = createMockRunner('test end', 'test end');
         runner.total = expectedTotal;
-        Progress.call({}, runner, expectedOptions);
-
-        process.stdout.write = stdoutWrite;
+        var stdout = runReporter({}, runner, expectedOptions);
 
         expect(stdout, 'to equal', []);
 
@@ -93,9 +92,8 @@ describe('Progress reporter', function() {
         };
         runner = createMockRunner('test end', 'test end');
         runner.total = expectedTotal;
-        Progress.call({}, runner, options);
+        var stdout = runReporter({}, runner, options);
 
-        process.stdout.write = stdoutWrite;
         var expectedArray = [
           '\u001b[J',
           '  ' + expectedOpen,
@@ -122,16 +120,16 @@ describe('Progress reporter', function() {
       };
       runner = createMockRunner('end', 'end');
       var calledEpilogue = false;
-      Progress.call(
+      runReporter(
         {
           epilogue: function() {
             calledEpilogue = true;
           }
         },
-        runner
+        runner,
+        {}
       );
 
-      process.stdout.write = stdoutWrite;
       expect(calledEpilogue, 'to be', true);
       expect(calledCursorShow, 'to be', true);
 
diff --git a/test/reporters/spec.spec.js b/test/reporters/spec.spec.js
index 2f4eee33e5..5f7584e33e 100644
--- a/test/reporters/spec.spec.js
+++ b/test/reporters/spec.spec.js
@@ -5,28 +5,23 @@ var Spec = reporters.Spec;
 var Base = reporters.Base;
 
 var createMockRunner = require('./helpers').createMockRunner;
+var makeRunReporter = require('./helpers.js').createRunReporterFunction;
 
 describe('Spec reporter', function() {
-  var stdout;
-  var stdoutWrite;
   var runner;
+  var options = {};
+  var runReporter = makeRunReporter(Spec);
   var useColors;
   var expectedTitle = 'expectedTitle';
 
   beforeEach(function() {
-    stdout = [];
-    stdoutWrite = process.stdout.write;
-    process.stdout.write = function(string, enc, callback) {
-      stdout.push(string);
-      stdoutWrite.call(process.stdout, string, enc, callback);
-    };
     useColors = Base.useColors;
     Base.useColors = false;
   });
 
   afterEach(function() {
     Base.useColors = useColors;
-    process.stdout.write = stdoutWrite;
+    runner = undefined;
   });
 
   describe('on suite', function() {
@@ -35,8 +30,7 @@ describe('Spec reporter', function() {
         title: expectedTitle
       };
       runner = createMockRunner('suite', 'suite', null, null, suite);
-      Spec.call({epilogue: function() {}}, runner);
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter({epilogue: function() {}}, runner, options);
       var expectedArray = [expectedTitle + '\n'];
       expect(stdout, 'to equal', expectedArray);
     });
@@ -47,8 +41,7 @@ describe('Spec reporter', function() {
         title: expectedTitle
       };
       runner = createMockRunner('pending test', 'pending', null, null, suite);
-      Spec.call({epilogue: function() {}}, runner);
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter({epilogue: function() {}}, runner, options);
       var expectedArray = ['  - ' + expectedTitle + '\n'];
       expect(stdout, 'to equal', expectedArray);
     });
@@ -65,8 +58,7 @@ describe('Spec reporter', function() {
           }
         };
         runner = createMockRunner('pass', 'pass', null, null, test);
-        Spec.call({epilogue: function() {}}, runner);
-        process.stdout.write = stdoutWrite;
+        var stdout = runReporter({epilogue: function() {}}, runner, options);
         var expectedString =
           '  ' +
           Base.symbols.ok +
@@ -90,8 +82,7 @@ describe('Spec reporter', function() {
           }
         };
         runner = createMockRunner('pass', 'pass', null, null, test);
-        Spec.call({epilogue: function() {}}, runner);
-        process.stdout.write = stdoutWrite;
+        var stdout = runReporter({epilogue: function() {}}, runner, options);
         var expectedString =
           '  ' + Base.symbols.ok + ' ' + expectedTitle + '\n';
         expect(stdout[0], 'to be', expectedString);
@@ -105,8 +96,7 @@ describe('Spec reporter', function() {
         title: expectedTitle
       };
       runner = createMockRunner('fail', 'fail', null, null, test);
-      Spec.call({epilogue: function() {}}, runner);
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter({epilogue: function() {}}, runner, options);
       var expectedArray = ['  ' + functionCount + ') ' + expectedTitle + '\n'];
       expect(stdout, 'to equal', expectedArray);
     });
diff --git a/test/reporters/tap.spec.js b/test/reporters/tap.spec.js
index 5030cbde5c..208a88b904 100644
--- a/test/reporters/tap.spec.js
+++ b/test/reporters/tap.spec.js
@@ -4,22 +4,17 @@ var reporters = require('../../').reporters;
 var TAP = reporters.TAP;
 
 var createMockRunner = require('./helpers').createMockRunner;
+var makeRunReporter = require('./helpers.js').createRunReporterFunction;
 
 describe('TAP reporter', function() {
-  var stdout;
-  var stdoutWrite;
   var runner;
+  var options = {};
+  var runReporter = makeRunReporter(TAP);
   var expectedTitle = 'some title';
   var countAfterTestEnd = 2;
   var test;
 
   beforeEach(function() {
-    stdout = [];
-    stdoutWrite = process.stdout.write;
-    process.stdout.write = function(string, enc, callback) {
-      stdout.push(string);
-      stdoutWrite.call(process.stdout, string, enc, callback);
-    };
     test = {
       fullTitle: function() {
         return expectedTitle;
@@ -29,7 +24,7 @@ describe('TAP reporter', function() {
   });
 
   afterEach(function() {
-    process.stdout.write = stdoutWrite;
+    runner = undefined;
   });
 
   describe('on start', function() {
@@ -43,10 +38,9 @@ describe('TAP reporter', function() {
         expectedString = string;
         return expectedTotal;
       };
-      TAP.call({}, runner);
+      var stdout = runReporter({}, runner, options);
 
       var expectedArray = ['1..' + expectedTotal + '\n'];
-      process.stdout.write = stdoutWrite;
 
       expect(stdout, 'to equal', expectedArray);
       expect(expectedString, 'to be', expectedSuite);
@@ -64,9 +58,7 @@ describe('TAP reporter', function() {
       );
       runner.suite = '';
       runner.grepTotal = function() {};
-      TAP.call({}, runner);
-
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter({}, runner, options);
 
       var expectedMessage =
         'ok ' + countAfterTestEnd + ' ' + expectedTitle + ' # SKIP -\n';
@@ -80,9 +72,7 @@ describe('TAP reporter', function() {
 
       runner.suite = '';
       runner.grepTotal = function() {};
-      TAP.call({}, runner);
-
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter({}, runner, options);
 
       var expectedMessage =
         'ok ' + countAfterTestEnd + ' ' + expectedTitle + '\n';
@@ -105,6 +95,7 @@ describe('TAP reporter', function() {
         var error = {
           message: expectedErrorMessage
         };
+        runner = createMockRunner('test end fail', 'test end', 'fail');
         runner.on = function(event, callback) {
           if (event === 'test end') {
             callback();
@@ -115,9 +106,7 @@ describe('TAP reporter', function() {
         };
         runner.suite = '';
         runner.grepTotal = function() {};
-        TAP.call({}, runner);
-
-        process.stdout.write = stdoutWrite;
+        var stdout = runReporter({}, runner, options);
 
         var expectedArray = [
           'not ok ' + countAfterTestEnd + ' ' + expectedTitle + '\n',
@@ -142,9 +131,7 @@ describe('TAP reporter', function() {
         );
         runner.suite = '';
         runner.grepTotal = function() {};
-        TAP.call({}, runner);
-
-        process.stdout.write = stdoutWrite;
+        var stdout = runReporter({}, runner, options);
 
         var expectedArray = [
           'not ok ' + countAfterTestEnd + ' ' + expectedTitle + '\n',
@@ -169,6 +156,7 @@ describe('TAP reporter', function() {
           stack: expectedStack,
           message: expectedErrorMessage
         };
+        runner = createMockRunner('test end fail', 'test end', 'fail');
         runner.on = function(event, callback) {
           if (event === 'test end') {
             callback();
@@ -179,9 +167,7 @@ describe('TAP reporter', function() {
         };
         runner.suite = '';
         runner.grepTotal = function() {};
-        TAP.call({}, runner);
-
-        process.stdout.write = stdoutWrite;
+        var stdout = runReporter({}, runner, options);
 
         var expectedArray = [
           'not ok ' + countAfterTestEnd + ' ' + expectedTitle + '\n',
@@ -193,6 +179,7 @@ describe('TAP reporter', function() {
     });
     describe('if there is no error stack or error message', function() {
       it('should write expected message only', function() {
+        runner = createMockRunner('test end fail', 'test end', 'fail');
         var error = {};
         runner.on = runner.once = function(event, callback) {
           if (event === 'test end') {
@@ -204,9 +191,7 @@ describe('TAP reporter', function() {
         };
         runner.suite = '';
         runner.grepTotal = function() {};
-        TAP.call({}, runner);
-
-        process.stdout.write = stdoutWrite;
+        var stdout = runReporter({}, runner, options);
 
         var expectedArray = [
           'not ok ' + countAfterTestEnd + ' ' + expectedTitle + '\n'
@@ -223,9 +208,7 @@ describe('TAP reporter', function() {
       runner = createMockRunner('fail end pass', 'fail', 'end', 'pass', test);
       runner.suite = '';
       runner.grepTotal = function() {};
-      TAP.call({}, runner);
-
-      process.stdout.write = stdoutWrite;
+      var stdout = runReporter({}, runner, options);
 
       var totalTests = numberOfPasses + numberOfFails;
       var expectedArray = [