From 2221d233bfbc50e387f1f0a45c085115e1e2959c Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Tue, 8 Dec 2015 18:22:38 +0000 Subject: [PATCH] wip! use tap.spawn() for each test --- test/nyc-test.js | 174 +++++++++++++++++++++++++++++++---------------- 1 file changed, 116 insertions(+), 58 deletions(-) diff --git a/test/nyc-test.js b/test/nyc-test.js index b0441721f..685fdcd26 100644 --- a/test/nyc-test.js +++ b/test/nyc-test.js @@ -1,5 +1,3 @@ -/* global describe, it */ - var _ = require('lodash') var fs = require('fs') var NYC = require('../') @@ -7,41 +5,118 @@ var path = require('path') var rimraf = require('rimraf') var sinon = require('sinon') var spawn = require('child_process').spawn +var tap = require('tap') +var tapMocha = require('tap/lib/mocha') require('chai').should() -require('tap').mochaGlobals() - -describe('nyc', function () { - var fixtures = path.resolve(__dirname, './fixtures') - describe('cwd', function () { - function afterEach () { - delete process.env.NYC_CWD - rimraf.sync(path.resolve(fixtures, './nyc_output')) +// All NYC instances that need to access disk should use fixturesDir as their +// working directory. +var fixturesDir = path.join(__dirname, 'fixtures') +// The instances use a .nyc_output directory within the fixturesDir. This makes +// it easier to clean up the data. +var tempDir = path.join(fixturesDir, '.nyc_output') +// Track all instances created in this process, to be cleaned up when the test +// is done. +var instances = [] +// Wrapper to instantiate NYC, forcing the tempDirectory option. +function instantiate (opts) { + opts = _.assign({ tempDirectory: tempDir }, opts) + var nyc = new NYC(opts) + instances.push(nyc) + return nyc +} +// Deletes the .nyc_output directory. Overrides writeCoverageFile() on each +// instance in case it wants to write coverage when the process exits. +function cleanup () { + instances.forEach(function (nyc) { + nyc.writeCoverageFile = function () {} + }) + instances = [] + rimraf.sync(tempDir) +} + +// If set, NYC_TEST_SPAWN contains the index of the test that should be +// executed. Otherwise the test runner should be initialized. +var spawnNthTest = parseInt(process.env.NYC_TEST_SPAWN || '-1', 10) +// Increased after every call to it() below, allows for the current test to be +// executed when in a tap.spawn() process. +var testCounter = 0 +// Keep track of the nested tests. Deepest nested test is first. +var stack = [tap.current()] + +// describe() and it() adopted from tap's mocha interface. +function describe (name, fn) { + if (spawnNthTest === -1) { + // Initialize the test runner. + var c = stack[0] + if (!fn) { + c.test(name) + } else { + c.test(name, function (tt) { + stack.unshift(tt) + fn() + stack.shift() + tt.end() + }) + } + } else if (fn) { + // Execute the function in order to get to the test that needs to be executed. + fn() + } +} + +function it (name, fn) { + if (spawnNthTest === -1) { + // Initialize the test runner. It'll have to run the current file through + // tap.spawn(), setting the NYC_TEST_SPAWN variable. + if (fn) { + stack[0].spawn(process.execPath, process.argv.slice(1), { env: { NYC_TEST_SPAWN: testCounter } }, '(in child process)') + } else { + tapMocha.it(name) } + } else if (spawnNthTest === testCounter) { + // Execute this test. + tapMocha.it(name, function (done) { + try { + if (fn.length) { + fn(function (err) { + cleanup() + done(err) + }) + } else { + fn() + cleanup() + done() + } + } catch (err) { + cleanup() + done(err) + } + }) + } - it('sets cwd to process.cwd() if no environment variable is set', function () { - var nyc = new NYC() + testCounter++ +} +describe('nyc', function () { + describe('cwd', function () { + it('sets cwd to process.cwd() if no environment variable is set', function () { + var nyc = instantiate() nyc.cwd.should.eql(process.cwd()) - afterEach() }) it('uses NYC_CWD environment variable for cwd if it is set', function () { - process.env.NYC_CWD = path.resolve(__dirname, './fixtures') - - var nyc = new NYC() + process.env.NYC_CWD = fixturesDir - nyc.cwd.should.equal(path.resolve(__dirname, './fixtures')) - afterEach() + var nyc = instantiate() + nyc.cwd.should.equal(fixturesDir) }) }) describe('config', function () { it("loads 'exclude' patterns from package.json", function () { - var nyc = new NYC({ - cwd: path.resolve(__dirname, './fixtures') - }) + var nyc = instantiate({ cwd: fixturesDir }) nyc.exclude.length.should.eql(5) }) @@ -65,7 +140,7 @@ describe('nyc', function () { describe('shouldInstrumentFile', function () { it('should exclude appropriately with defaults', function () { - var nyc = new NYC() + var nyc = instantiate() // Root package contains config.exclude // Restore exclude to default patterns @@ -89,9 +164,7 @@ describe('nyc', function () { }) it('should exclude appropriately with config.exclude', function () { - var nyc = new NYC({ - cwd: fixtures - }) + var nyc = instantiate({ cwd: fixturesDir }) var shouldInstrumentFile = nyc.shouldInstrumentFile.bind(nyc) // config.excludes: "blarg", "blerg" @@ -102,9 +175,7 @@ describe('nyc', function () { }) it('should handle example symlinked node_module', function () { - var nyc = new NYC({ - cwd: fixtures - }) + var nyc = instantiate({ cwd: fixturesDir }) var shouldInstrumentFile = nyc.shouldInstrumentFile.bind(nyc) var relPath = '../../nyc/node_modules/glob/glob.js' @@ -121,7 +192,7 @@ describe('nyc', function () { }) it('allows a file to be included rather than excluded', function () { - var nyc = new NYC() + var nyc = instantiate() // Root package contains config.exclude // Restore exclude to default patterns @@ -137,10 +208,7 @@ describe('nyc', function () { describe('wrap', function () { it('wraps modules with coverage counters when they are required', function () { - var nyc = new NYC({ - cwd: process.cwd() - }) - nyc.wrap() + instantiate().wrap() // clear the module cache so that // we pull index.js in again and wrap it. @@ -158,10 +226,7 @@ describe('nyc', function () { module._compile(fs.readFileSync(filename, 'utf8')) }) - var nyc = new NYC({ - cwd: process.cwd() - }) - nyc.wrap() + instantiate().wrap() // clear the module cache so that // we pull index.js in again and wrap it. @@ -209,9 +274,7 @@ describe('nyc', function () { }) it('does not output coverage for files that have not been included, by default', function (done) { - var nyc = (new NYC({ - cwd: process.cwd() - })).wrap() + var nyc = instantiate().wrap() var reports = _.filter(nyc._loadReports(), function (report) { return report['./test/fixtures/not-loaded.js'] @@ -292,8 +355,8 @@ describe('nyc', function () { it('handles multiple reporters', function (done) { var reporters = ['text-summary', 'text-lcov'] var incr = 0 - var nyc = new NYC({ - cwd: process.cwd(), + var nyc = instantiate({ + cwd: fixturesDir, reporter: reporters }) var proc = spawn(process.execPath, ['./test/fixtures/sigint.js'], { @@ -339,18 +402,14 @@ describe('nyc', function () { it('it handles having no .istanbul.yml in the root directory', function (done) { afterEach() - var nyc = new NYC() - nyc.wrap() + instantiate().wrap() return done() }) it('uses the values in .istanbul.yml to instantiate the instrumenter', function (done) { writeConfig() - var nyc = new NYC({ - istanbul: istanbul - }) - nyc.wrap() + instantiate({ istanbul: istanbul }).wrap() istanbul.config.loadFile.calledWithMatch('.istanbul.yml').should.equal(true) istanbul.Instrumenter.calledWith({ @@ -365,11 +424,10 @@ describe('nyc', function () { }) it('loads the .istanbul.yml configuration from NYC_CWD', function (done) { - var nyc = new NYC({ + instantiate({ istanbul: istanbul, cwd: './test/fixtures' - }) - nyc.wrap() + }).wrap() istanbul.config.loadFile.calledWithMatch(path.join('test', 'fixtures', '.istanbul.yml')).should.equal(true) istanbul.Instrumenter.calledWith({ @@ -396,7 +454,7 @@ describe('nyc', function () { var yargv = require('yargs').argv - var munged = (new NYC()).mungeArgs(yargv) + var munged = instantiate().mungeArgs(yargv) munged.should.eql(['node', 'test/nyc-test.js']) }) @@ -404,7 +462,7 @@ describe('nyc', function () { describe('addAllFiles', function () { it('outputs an empty coverage report for all files that are not excluded', function (done) { - var nyc = (new NYC()) + var nyc = instantiate() nyc.addAllFiles() var reports = _.filter(nyc._loadReports(), function (report) { @@ -419,16 +477,16 @@ describe('nyc', function () { }) it('tracks coverage appropriately once the file is required', function (done) { - var nyc = (new NYC({ - cwd: process.cwd() - })).wrap() + var nyc = instantiate({ + cwd: fixturesDir + }).wrap() require('./fixtures/not-loaded') nyc.writeCoverageFile() var reports = _.filter(nyc._loadReports(), function (report) { - return report['./test/fixtures/not-loaded.js'] + return report['./not-loaded.js'] }) - var report = reports[0]['./test/fixtures/not-loaded.js'] + var report = reports[0]['./not-loaded.js'] reports.length.should.equal(1) report.s['1'].should.equal(1)