├── .travis.yml ├── .gitignore ├── test ├── fixtures │ ├── lib │ │ ├── subtract.coffee │ │ ├── divide.coffee │ │ ├── add.js │ │ └── multiply.js │ └── test │ │ ├── subtract.coffee │ │ └── add.js ├── .jshintrc └── main.js ├── .editorconfig ├── .jshintrc ├── LICENSE-MIT ├── package.json ├── index.js └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | cov-foo/ 4 | *.orig 5 | -------------------------------------------------------------------------------- /test/fixtures/lib/subtract.coffee: -------------------------------------------------------------------------------- 1 | exports.subtract = (a, b) -> a - b 2 | 3 | exports.missed = -> "not covered" 4 | -------------------------------------------------------------------------------- /test/fixtures/lib/divide.coffee: -------------------------------------------------------------------------------- 1 | exports.multiply = (a, b) -> a / b 2 | 3 | exports.missed = -> "This entire file is not covered because it's never required." 4 | -------------------------------------------------------------------------------- /test/fixtures/lib/add.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.add = function (a, b) { 4 | return a + b; 5 | }; 6 | 7 | exports.missed = function () { 8 | return "not covered"; 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/test/subtract.coffee: -------------------------------------------------------------------------------- 1 | assert = require('assert') 2 | mod = require('../lib/subtract') 3 | 4 | describe '#subtract', -> 5 | it 'subtracts numbers', -> 6 | assert.equal(mod.subtract(2, 1), 1) 7 | return 8 | -------------------------------------------------------------------------------- /test/fixtures/lib/multiply.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.multiply = function (a, b) { 4 | return a * b; 5 | }; 6 | 7 | exports.missed = function () { 8 | return "This entire file is not covered because it's never required."; 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/test/add.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var mod = require('../lib/add'); 5 | 6 | describe('#add', function () { 7 | it('add numbers', function () { 8 | assert.equal(mod.add(1, 1), 2); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.jshintrc", 3 | "globals": { 4 | "describe": false, 5 | "it": false, 6 | "beforeEach": false, 7 | "afterEach": false, 8 | "before": false, 9 | "after": false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [test/fixtures/*] 15 | insert_final_newline = false 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "bitwise": true, 4 | "camelcase": true, 5 | "eqeqeq": true, 6 | "forin": true, 7 | "freeze": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "noempty": true, 14 | "nonew": true, 15 | "regexp": true, 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "trailing": true, 20 | "smarttabs": true, 21 | "white": true 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright 2014 Matt Blair 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-coffee-istanbul", 3 | "version": "0.9.1", 4 | "description": "Istanbul coffee and js unit test coverage plugin for gulp.", 5 | "keywords": [ 6 | "gulp", 7 | "gulp-plugin", 8 | "JavaScript", 9 | "CoffeeScript", 10 | "coverage", 11 | "istanbul", 12 | "unit test" 13 | ], 14 | "homepage": "https://github.com/duereg/gulp-coffee-istanbul", 15 | "bugs": "https://github.com/duereg/gulp-coffee-istanbul/issues", 16 | "author": { 17 | "name": "Matt Blair", 18 | "email": "matt@mattblair.co", 19 | "url": "https://github.com/duereg" 20 | }, 21 | "main": "./index.js", 22 | "repository": { 23 | "type": "git", 24 | "url": "git://github.com/duereg/gulp-coffee-istanbul.git" 25 | }, 26 | "scripts": { 27 | "pretest": "jshint index.js ./test/.", 28 | "test": "mocha -R spec" 29 | }, 30 | "dependencies": { 31 | "coffee-script": "^1.9.0", 32 | "gulp-util": "^3.0.2", 33 | "ibrik": "^2.0.0", 34 | "istanbul-traceur": "duereg/istanbul-traceur", 35 | "lodash": "^4.14.0", 36 | "through2": "^2.0.1" 37 | }, 38 | "devDependencies": { 39 | "gulp": "^3.9.1", 40 | "gulp-mocha": "^2.2.0", 41 | "jshint": "^2.9.2", 42 | "mocha": "^2.5.3", 43 | "rimraf": "^2.5.4" 44 | }, 45 | "peerDependencies": { 46 | "traceur": ">= 0.0.61 < 0.1.0" 47 | }, 48 | "licenses": [ 49 | { 50 | "type": "MIT" 51 | } 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var through = require('through2').obj; 4 | var path = require('path'); 5 | var istanbul = require('istanbul-traceur'); 6 | var CoffeeInstrumenter = require('ibrik').Instrumenter; 7 | var gutil = require('gulp-util'); 8 | var _ = require('lodash'); 9 | var Report = istanbul.Report; 10 | var Collector = istanbul.Collector; 11 | var PluginError = gutil.PluginError; 12 | 13 | var PLUGIN_NAME = 'gulp-coffee-istanbul'; 14 | var COVERAGE_VARIABLE = '$$cov_' + new Date().getTime() + '$$'; 15 | 16 | var plugin = module.exports = function (opts) { 17 | opts = opts || {}; 18 | opts.includeUntested = opts.includeUntested === true; 19 | if (!opts.coverageVariable) opts.coverageVariable = COVERAGE_VARIABLE; 20 | 21 | var jsInstrumenter = new istanbul.Instrumenter(opts); 22 | var coffeeInstrumenter = new CoffeeInstrumenter(opts); 23 | 24 | return through(function (file, enc, cb) { 25 | cb = _.once(cb); 26 | if (!(file.contents instanceof Buffer)) { 27 | return cb(new PluginError(PLUGIN_NAME, 'streams not supported')); 28 | } 29 | 30 | var instrumentHelper = function (err, code) { 31 | if (err) { 32 | return cb(new PluginError( 33 | PLUGIN_NAME, 34 | 'Unable to parse ' + file.path + '\n\n' + err.message + '\n' 35 | )); 36 | } 37 | 38 | file.contents = new Buffer(code); 39 | 40 | // Parse the blank coverage object from the instrumented file and save it 41 | // to the global coverage variable to enable reporting on non-required 42 | // files, a workaround for 43 | // https://github.com/gotwarlost/istanbul/issues/112 44 | if (opts.includeUntested) { 45 | var instrumentedSrc = file.contents.toString(); 46 | var covStubRE = /\{.*"path".*"fnMap".*"statementMap".*"branchMap".*\}/g; 47 | var covStubMatch = covStubRE.exec(instrumentedSrc); 48 | if (covStubMatch !== null) { 49 | var covStub = JSON.parse(covStubMatch[0]); 50 | global[opts.coverageVariable] = global[opts.coverageVariable] || {}; 51 | global[opts.coverageVariable][path.resolve(file.path)] = covStub; 52 | } 53 | } 54 | 55 | return cb(err, file); 56 | }; 57 | 58 | if (path.extname(file.path) === '.js') { 59 | jsInstrumenter.instrument(file.contents.toString(), file.path, instrumentHelper); 60 | } else if (path.extname(file.path) === '.coffee') { 61 | coffeeInstrumenter.instrument(file.contents.toString(), file.path, instrumentHelper); 62 | } 63 | 64 | }); 65 | }; 66 | 67 | plugin.hookRequire = function () { 68 | var fileMap = {}; 69 | 70 | istanbul.hook.hookRequire(function (path) { 71 | return !!fileMap[path]; 72 | }, function (code, path) { 73 | return fileMap[path]; 74 | }); 75 | 76 | return through(function (file, enc, cb) { 77 | // If the file is already required, delete it from the cache otherwise the covered 78 | // version will be ignored. 79 | delete require.cache[path.resolve(file.path)]; 80 | fileMap[file.path] = file.contents.toString(); 81 | return cb(); 82 | }); 83 | }; 84 | 85 | plugin.summarizeCoverage = function (opts) { 86 | opts = opts || {}; 87 | if (!opts.coverageVariable) opts.coverageVariable = COVERAGE_VARIABLE; 88 | 89 | if (!global[opts.coverageVariable]) throw new Error('no coverage data found, run tests before calling `summarizeCoverage`'); 90 | 91 | var collector = new Collector(); 92 | collector.add(global[opts.coverageVariable]); 93 | var finalCoverage = collector.getFinalCoverage(); 94 | 95 | return istanbul.utils.summarizeCoverage(finalCoverage); 96 | }; 97 | 98 | plugin.writeReports = function (opts) { 99 | if (typeof opts === 'string') opts = { dir: opts }; 100 | opts = opts || {}; 101 | 102 | var defaultDir = path.join(process.cwd(), 'coverage'); 103 | opts = _.defaults(opts, { 104 | coverageVariable: COVERAGE_VARIABLE, 105 | dir: defaultDir, 106 | reporters: [ 'lcov', 'json', 'text', 'text-summary' ], 107 | reportOpts: { dir: opts.dir || defaultDir } 108 | }); 109 | 110 | var invalid = _.difference(opts.reporters, Report.getReportList()); 111 | if (invalid.length) { 112 | // throw before we start -- fail fast 113 | throw new PluginError(PLUGIN_NAME, 'Invalid reporters: ' + invalid.join(', ')); 114 | } 115 | 116 | var reporters = opts.reporters.map(function (r) { 117 | return Report.create(r, _.clone(opts.reportOpts)); 118 | }); 119 | 120 | var cover = through(); 121 | 122 | cover.on('end', function () { 123 | var collector = new Collector(); 124 | 125 | // revert to an object if there are not matching source files. 126 | collector.add(global[opts.coverageVariable] || {}); 127 | 128 | reporters.forEach(function (report) { 129 | report.writeReport(collector, true); 130 | }); 131 | }).resume(); 132 | 133 | return cover; 134 | }; 135 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][depstat-image]][depstat-url] 2 | 3 | gulp-coffee-istanbul 4 | =========================== 5 | 6 | [Istanbul][istanbul] unit test coverage plugin for [gulp][gulp], covering coffee and javascript. 7 | 8 | Allows for in-place testing and coverage of coffee files without the need for compiling and linking to the compiled source. 9 | 10 | Almost entirely stolen from Simon Boudrias and his gulp plugin [gulp-istanbul][original-plugin]. 11 | 12 | Works on top of any Node.js unit test framework. 13 | 14 | Installation 15 | --------------- 16 | 17 | ```shell 18 | npm install --save-dev gulp-coffee-istanbul 19 | ``` 20 | 21 | Example 22 | --------------- 23 | 24 | In your `gulpfile.js`: 25 | 26 | #### Node.js testing 27 | 28 | ```coffee 29 | istanbul = require('gulp-coffee-istanbul') 30 | # We'll use mocha here, but any test framework will work 31 | mocha = require('gulp-mocha') 32 | 33 | jsFiles = ['config/**/*.js', 'controllers/**/*.js', 'models/**/*.js', 'app.js'] 34 | specFiles = ['spec/**/*.coffee'] 35 | coffeeFiles = ['src/**/*.coffee'] 36 | 37 | gulp.task 'test', -> 38 | gulp.src jsFiles.concat(coffeeFiles) 39 | .pipe istanbul({includeUntested: true}) # Covering files 40 | .pipe istanbul.hookRequire() 41 | .on 'finish', -> 42 | gulp.src specFiles 43 | .pipe mocha reporter: 'spec' 44 | .pipe istanbul.writeReports() # Creating the reports after tests run 45 | ``` 46 | 47 | #### Browser testing 48 | 49 | For browser testing, you'll need to write the files covered by istanbul in a directory from where you'll serve these files to the browser running the test. You'll also need a way to extract the value of the [coverage variable](#coveragevariable) after the test have runned in the browser. 50 | 51 | Browser testing is hard. If you're not sure what to do, then I suggest you take a look at [Karma test runner](http://karma-runner.github.io) - it has built-in coverage using Istanbul. 52 | 53 | 54 | ```javascript 55 | var istanbul = require('gulp-coffee-istanbul'); 56 | 57 | gulp.task('test', function (cb) { 58 | gulp.src(['lib/**/*.js', 'main.js']) 59 | .pipe(istanbul()) // Covering files 60 | .pipe(gulp.dest('test-tmp/')) 61 | .on('finish', function () { 62 | gulp.src(['test/*.html']) 63 | .pipe(testFramework()) 64 | .pipe(istanbul.writeReports()) // Creating the reports after tests runned 65 | .on('end', cb); 66 | }); 67 | }); 68 | ``` 69 | 70 | API 71 | -------------- 72 | 73 | ### istanbul(opt) 74 | 75 | Instrument files passed in the stream. 76 | 77 | #### opt 78 | Type: `Object` (optional) 79 | ```js 80 | { 81 | coverageVariable: 'someVariable', 82 | ...other Instrumeter options... 83 | } 84 | ``` 85 | 86 | ##### coverageVariable 87 | Type: `String` (optional) 88 | Default: `'$$cov_' + new Date().getTime() + '$$'` 89 | 90 | The global variable istanbul uses to store coverage 91 | 92 | See also: 93 | - [istanbul coverageVariable][istanbul-coverage-variable] 94 | - [SanboxedModule][sandboxed-module-coverage-variable] 95 | 96 | ##### includeUntested 97 | Type: `Boolean` (optional) 98 | Default: `false` 99 | 100 | Flag to include test coverage of files that aren't `require`d by any tests 101 | 102 | See also: 103 | - [istanbul "0% coverage" issue](https://github.com/gotwarlost/istanbul/issues/112) 104 | 105 | ##### Other Istanbul Instrumenter options 106 | 107 | See: 108 | - [istanbul Instrumenter documentation][istanbul-coverage-variable] 109 | 110 | ### istanbul.hookRequire() 111 | 112 | Overwrite `require` so it returns the covered files. 113 | 114 | Always use this option if you're running tests in Node.js 115 | 116 | ### istanbul.summarizeCoverage(opt) 117 | 118 | get coverage summary details 119 | 120 | #### opt 121 | Type: `Object` (optional) 122 | ```js 123 | { 124 | coverageVariable: 'someVariable' 125 | } 126 | ``` 127 | ##### coverageVariable 128 | Type: `String` (optional) 129 | Default: `'$$cov_' + new Date().getTime() + '$$'` 130 | 131 | The global variable istanbul uses to store coverage 132 | 133 | See also: 134 | - [istanbul coverageVariable][istanbul-coverage-variable] 135 | - [SanboxedModule][sandboxed-module-coverage-variable] 136 | 137 | #### returns 138 | Type: `Object` 139 | ```js 140 | { 141 | lines: { total: 4, covered: 2, skipped: 0, pct: 50 }, 142 | statements: { total: 4, covered: 2, skipped: 0, pct: 50 }, 143 | functions: { total: 2, covered: 0, skipped: 0, pct: 0 }, 144 | branches: { total: 0, covered: 0, skipped: 0, pct: 100 } 145 | } 146 | ``` 147 | 148 | See also: 149 | - [istanbul utils.summarizeCoverage()][istanbul-summarize-coverage] 150 | 151 | 152 | ### istanbul.writeReports(opt) 153 | 154 | Create the reports on stream end. 155 | 156 | #### opt 157 | Type: `Object` (optional) 158 | ```js 159 | { 160 | dir: './coverage', 161 | reporters: [ 'lcov', 'json', 'text', 'text-summary' ], 162 | reportOpts: { dir: './coverage' }, 163 | coverageVariable: 'someVariable' 164 | } 165 | ``` 166 | 167 | #### dir 168 | Type: `String` (optional) 169 | Default: `./coverage` 170 | 171 | The folder in which the reports are to be outputted. 172 | 173 | #### reporters 174 | Type: `Array` (optional) 175 | Default: `[ 'lcov', 'json', 'text', 'text-summary' ]` 176 | 177 | The list of available reporters: 178 | - `clover` 179 | - `cobertura` 180 | - `html` 181 | - `json` 182 | - `lcov` 183 | - `lcovonly` 184 | - `none` 185 | - `teamcity` 186 | - `text` 187 | - `text-summary` 188 | 189 | See also `require('istanbul').Report.getReportList()` 190 | 191 | ##### coverageVariable 192 | Type: `String` (optional) 193 | Default: `'$$cov_' + new Date().getTime() + '$$'` 194 | 195 | The global variable istanbul uses to store coverage 196 | 197 | See also: 198 | - [istanbul coverageVariable][istanbul-coverage-variable] 199 | - [SanboxedModule][sandboxed-module-coverage-variable] 200 | 201 | License 202 | ------------ 203 | 204 | [MIT License](http://en.wikipedia.org/wiki/MIT_License) (c) Matt Blair - 2015 205 | 206 | [istanbul]: http://gotwarlost.github.io/istanbul/ 207 | [gulp]: https://github.com/gulpjs/gulp 208 | [original-plugin]: https://github.com/SBoudrias/gulp-istanbul 209 | 210 | [npm-url]: https://npmjs.org/package/gulp-coffee-istanbul 211 | [npm-image]: https://badge.fury.io/js/gulp-coffee-istanbul.svg 212 | 213 | [travis-url]: http://travis-ci.org/duereg/gulp-coffee-istanbul 214 | [travis-image]: https://secure.travis-ci.org/duereg/gulp-coffee-istanbul.svg?branch=master 215 | 216 | [depstat-url]: https://david-dm.org/duereg/gulp-coffee-istanbul 217 | [depstat-image]: https://david-dm.org/duereg/gulp-coffee-istanbul.svg 218 | 219 | [istanbul-coverage-variable]: http://gotwarlost.github.io/istanbul/public/apidocs/classes/Instrumenter.html 220 | [istanbul-summarize-coverage]: http://gotwarlost.github.io/istanbul/public/apidocs/classes/ObjectUtils.html#method_summarizeCoverage 221 | [sandboxed-module-coverage-variable]: https://github.com/felixge/node-sandboxed-module/blob/master/lib/sandboxed_module.js#L240 222 | -------------------------------------------------------------------------------- /test/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('coffee-script/register'); 4 | 5 | var fs = require('fs'); 6 | var assert = require('assert'); 7 | var rimraf = require('rimraf'); 8 | var gutil = require('gulp-util'); 9 | var gulp = require('gulp'); 10 | var istanbul = require('../'); 11 | var mocha = require('gulp-mocha'); 12 | 13 | var out = process.stdout.write.bind(process.stdout); 14 | 15 | describe('gulp-coffee-istanbul', function () { 16 | 17 | afterEach(function () { 18 | process.stdout.write = out; // put it back even if test fails 19 | require.cache = {}; 20 | }); 21 | 22 | var libFile = new gutil.File({ 23 | path: 'test/fixtures/lib/add.js', 24 | cwd: 'test/', 25 | base: 'test/fixtures/lib', 26 | contents: fs.readFileSync('test/fixtures/lib/add.js') 27 | }); 28 | 29 | describe('istanbul()', function () { 30 | beforeEach(function () { 31 | this.stream = istanbul(); 32 | }); 33 | 34 | it('instrument files', function (done) { 35 | this.stream.on('data', function (file) { 36 | assert.equal(file.path, libFile.path); 37 | assert(file.contents.toString().indexOf('__cov_') >= 0); 38 | assert(file.contents.toString().indexOf('$$cov_') >= 0); 39 | done(); 40 | }); 41 | 42 | this.stream.write(libFile); 43 | this.stream.end(); 44 | }); 45 | 46 | it('throw when receiving a stream', function (done) { 47 | var srcFile = new gutil.File({ 48 | path: 'test/fixtures/lib/add.js', 49 | cwd: 'test/', 50 | base: 'test/fixtures/lib', 51 | contents: fs.createReadStream('test/fixtures/lib/add.js') 52 | }); 53 | 54 | this.stream.on('error', function (err) { 55 | assert(err); 56 | done(); 57 | }); 58 | 59 | this.stream.write(srcFile); 60 | this.stream.end(); 61 | }); 62 | 63 | it('handles invalid JS files', function (done) { 64 | var srcFile = new gutil.File({ 65 | path: 'test/fixtures/lib/add.js', 66 | cwd: 'test/', 67 | base: 'test/fixtures/lib', 68 | contents: new Buffer('var a {}') 69 | }); 70 | this.stream.on('error', function (err) { 71 | assert(err.message.indexOf('test/fixtures/lib/add.js') >= 0); 72 | done(); 73 | }); 74 | this.stream.write(srcFile); 75 | this.stream.end(); 76 | }); 77 | }); 78 | 79 | describe('.hookRequire()', function () { 80 | it('clear covered files from require.cache', function (done) { 81 | var add1 = require('./fixtures/lib/add'); 82 | var stream = istanbul() 83 | .pipe(istanbul.hookRequire()) 84 | .on('finish', function () { 85 | var add2 = require('./fixtures/lib/add'); 86 | assert.notEqual(add1, add2); 87 | done(); 88 | }); 89 | stream.write(libFile); 90 | stream.end(); 91 | }); 92 | }); 93 | 94 | describe('when testing coffee', function() { 95 | var libPath, testPath; 96 | 97 | beforeEach(function() { 98 | libPath = [ 'test/fixtures/lib/*.coffee' ]; 99 | testPath = [ 'test/fixtures/test/*.coffee' ]; 100 | }); 101 | 102 | describe('istanbul.writeReports()', function () { 103 | beforeEach(function (done) { 104 | // set up coverage 105 | gulp.src(libPath) 106 | .pipe(istanbul()) 107 | .pipe(istanbul.hookRequire()) 108 | .on('finish', done); 109 | }); 110 | 111 | afterEach(function () { 112 | rimraf.sync('coverage'); 113 | rimraf.sync('cov-foo'); 114 | }); 115 | 116 | it('output coverage report', function (done) { 117 | gulp.src(testPath) 118 | .pipe(mocha()) 119 | .pipe(istanbul.writeReports()); 120 | 121 | process.stdout.write = function (str) { 122 | if (str.indexOf('==== Coverage summary ====') >= 0) { 123 | done(); 124 | } 125 | }; 126 | }); 127 | 128 | it('create coverage report', function (done) { 129 | process.stdout.write = function () {}; 130 | gulp.src(testPath) 131 | .pipe(mocha()) 132 | .pipe(istanbul.writeReports()) 133 | .on('end', function () { 134 | gutil.log('create coverage report!!! coffee!'); 135 | assert(fs.existsSync('./coverage')); 136 | assert(fs.existsSync('./coverage/lcov.info')); 137 | assert(fs.existsSync('./coverage/coverage-final.json')); 138 | done(); 139 | }); 140 | }); 141 | 142 | it('allow specifying report output dir (legacy way)', function (done) { 143 | process.stdout.write = function () {}; 144 | gulp.src(testPath) 145 | .pipe(mocha()) 146 | .pipe(istanbul.writeReports('cov-foo')) 147 | .on('end', function () { 148 | assert(fs.existsSync('./cov-foo')); 149 | assert(fs.existsSync('./cov-foo/lcov.info')); 150 | assert(fs.existsSync('./cov-foo/coverage-final.json')); 151 | done(); 152 | }); 153 | }); 154 | 155 | it('allow specifying report output dir', function (done) { 156 | process.stdout.write = function () {}; 157 | gulp.src(testPath) 158 | .pipe(mocha()) 159 | .pipe(istanbul.writeReports({ dir: 'cov-foo' })) 160 | .on('end', function () { 161 | assert(fs.existsSync('./cov-foo')); 162 | assert(fs.existsSync('./cov-foo/lcov.info')); 163 | assert(fs.existsSync('./cov-foo/coverage-final.json')); 164 | process.stdout.write = out; 165 | done(); 166 | }); 167 | }); 168 | 169 | it('allow specifying report output formats', function (done) { 170 | process.stdout.write = function () {}; 171 | gulp.src(testPath) 172 | .pipe(mocha()) 173 | .pipe(istanbul.writeReports({ dir: 'cov-foo', reporters: ['cobertura'] })) 174 | .on('end', function () { 175 | assert(fs.existsSync('./cov-foo')); 176 | assert(!fs.existsSync('./cov-foo/lcov.info')); 177 | assert(fs.existsSync('./cov-foo/cobertura-coverage.xml')); 178 | process.stdout.write = out; 179 | done(); 180 | }); 181 | }); 182 | 183 | }); 184 | 185 | describe('with defined coverageVariable option', function () { 186 | afterEach(function () { 187 | rimraf.sync('coverage'); 188 | }); 189 | 190 | it('allow specifying coverage variable', function (done) { 191 | process.stdout.write = function () {}; 192 | 193 | var coverageVariable = 'CUSTOM_COVERAGE_VARIABLE'; 194 | 195 | // set up coverage 196 | gulp.src(libPath) 197 | .pipe(istanbul({ coverageVariable: coverageVariable })) 198 | .pipe(istanbul.hookRequire()) 199 | .on('finish', function () { 200 | gulp.src(testPath) 201 | .pipe(mocha()) 202 | .pipe(istanbul.writeReports({ coverageVariable: coverageVariable })) 203 | .on('end', function () { 204 | assert(fs.existsSync('./coverage')); 205 | assert(fs.existsSync('./coverage/lcov.info')); 206 | assert(fs.existsSync('./coverage/coverage-final.json')); 207 | process.stdout.write = out; 208 | done(); 209 | }); 210 | }); 211 | }); 212 | }); 213 | }); 214 | 215 | describe('when testing js', function() { 216 | var libPath, testPath; 217 | 218 | beforeEach(function() { 219 | libPath = [ 'test/fixtures/lib/*.js' ]; 220 | testPath = [ 'test/fixtures/test/*.js' ]; 221 | }); 222 | 223 | afterEach(function() { 224 | process.stdout.write = out; 225 | }); 226 | 227 | describe('istanbul.summarizeCoverage()', function () { 228 | it('gets statistics about the test run', function (done) { 229 | var COV_VAR = 'CovVarJs'; 230 | process.stdout.write = function () {}; 231 | 232 | gulp.src(libPath) 233 | .pipe(istanbul({coverageVariable: COV_VAR})) 234 | .pipe(istanbul.hookRequire()) 235 | .on('finish', function () { 236 | console.log('inFinish'); 237 | gulp.src(testPath) 238 | .pipe(mocha()) 239 | .on('end', function () { 240 | process.stdout.write = out; 241 | var data = istanbul.summarizeCoverage({ 242 | coverageVariable: COV_VAR 243 | }); 244 | 245 | try{ 246 | assert.equal(data.lines.pct, 75); 247 | assert.equal(data.statements.pct, 75); 248 | assert.equal(data.functions.pct, 50); 249 | assert.equal(data.branches.pct, 100); 250 | done(); 251 | } catch (ex) { 252 | done(ex); 253 | } 254 | }); 255 | }); 256 | }); 257 | 258 | it('allows inclusion of untested files', function (done) { 259 | var COV_VAR = 'untestedCovVarJs'; 260 | process.stdout.write = function () {}; 261 | 262 | gulp.src(libPath) 263 | .pipe(istanbul({ 264 | coverageVariable: COV_VAR, 265 | includeUntested: true 266 | })) 267 | .pipe(istanbul.hookRequire()) 268 | .on('finish', function () { 269 | gulp.src(testPath) 270 | .pipe(mocha()) 271 | .on('end', function () { 272 | process.stdout.write = out; 273 | 274 | var data = istanbul.summarizeCoverage({ 275 | coverageVariable: COV_VAR 276 | }); 277 | 278 | // If untested files are included, line and statement coverage 279 | // drops to 25% 280 | try{ 281 | assert.equal(data.lines.pct, 37.5); 282 | assert.equal(data.statements.pct, 37.5); 283 | assert.equal(data.functions.pct, 25); 284 | assert.equal(data.branches.pct, 100); 285 | done(); 286 | } catch (ex) { 287 | done(ex); 288 | } 289 | }); 290 | }); 291 | }); 292 | }); 293 | 294 | describe('istanbul.writeReports()', function () { 295 | beforeEach(function (done) { 296 | // set up coverage 297 | gulp.src(libPath) 298 | .pipe(istanbul()) 299 | .pipe(istanbul.hookRequire()) 300 | .on('finish', done); 301 | }); 302 | 303 | afterEach(function () { 304 | rimraf.sync('coverage'); 305 | rimraf.sync('cov-foo'); 306 | }); 307 | 308 | it('output coverage report', function (done) { 309 | gulp.src(testPath) 310 | .pipe(mocha()) 311 | .pipe(istanbul.writeReports()); 312 | 313 | process.stdout.write = function (str) { 314 | if (str.indexOf('==== Coverage summary ====') >= 0) { 315 | done(); 316 | } 317 | }; 318 | }); 319 | 320 | it('create coverage report', function (done) { 321 | process.stdout.write = function () {}; 322 | gulp.src(testPath) 323 | .pipe(mocha()) 324 | .pipe(istanbul.writeReports()) 325 | .on('end', function () { 326 | assert(fs.existsSync('./coverage')); 327 | assert(fs.existsSync('./coverage/lcov.info')); 328 | assert(fs.existsSync('./coverage/coverage-final.json')); 329 | done(); 330 | }); 331 | }); 332 | 333 | it('allow specifying report output dir (legacy way)', function (done) { 334 | process.stdout.write = function () {}; 335 | gulp.src(testPath) 336 | .pipe(mocha()) 337 | .pipe(istanbul.writeReports('cov-foo')) 338 | .on('end', function () { 339 | assert(fs.existsSync('./cov-foo')); 340 | assert(fs.existsSync('./cov-foo/lcov.info')); 341 | assert(fs.existsSync('./cov-foo/coverage-final.json')); 342 | done(); 343 | }); 344 | }); 345 | 346 | it('allow specifying report output dir', function (done) { 347 | process.stdout.write = function () {}; 348 | gulp.src(testPath) 349 | .pipe(mocha()) 350 | .pipe(istanbul.writeReports({ dir: 'cov-foo' })) 351 | .on('end', function () { 352 | assert(fs.existsSync('./cov-foo')); 353 | assert(fs.existsSync('./cov-foo/lcov.info')); 354 | assert(fs.existsSync('./cov-foo/coverage-final.json')); 355 | process.stdout.write = out; 356 | done(); 357 | }); 358 | }); 359 | 360 | it('allow specifying report output formats', function (done) { 361 | process.stdout.write = function () {}; 362 | gulp.src(testPath) 363 | .pipe(mocha()) 364 | .pipe(istanbul.writeReports({ dir: 'cov-foo', reporters: ['cobertura'] })) 365 | .on('end', function () { 366 | assert(fs.existsSync('./cov-foo')); 367 | assert(!fs.existsSync('./cov-foo/lcov.info')); 368 | assert(fs.existsSync('./cov-foo/cobertura-coverage.xml')); 369 | process.stdout.write = out; 370 | done(); 371 | }); 372 | }); 373 | 374 | }); 375 | 376 | describe('with defined coverageVariable option', function () { 377 | afterEach(function () { 378 | rimraf.sync('coverage'); 379 | }); 380 | 381 | it('allow specifying coverage variable', function (done) { 382 | process.stdout.write = function () {}; 383 | 384 | var coverageVariable = 'CUSTOM_COVERAGE_VARIABLE'; 385 | 386 | // set up coverage 387 | gulp.src(libPath) 388 | .pipe(istanbul({ coverageVariable: coverageVariable })) 389 | .pipe(istanbul.hookRequire()) 390 | .on('finish', function () { 391 | gulp.src(testPath) 392 | .pipe(mocha()) 393 | .pipe(istanbul.writeReports({ coverageVariable: coverageVariable })) 394 | .on('end', function () { 395 | assert(fs.existsSync('./coverage')); 396 | assert(fs.existsSync('./coverage/lcov.info')); 397 | assert(fs.existsSync('./coverage/coverage-final.json')); 398 | process.stdout.write = out; 399 | done(); 400 | }); 401 | }); 402 | }); 403 | }); 404 | }); 405 | 406 | it('throws when specifying invalid reporters', function () { 407 | var actualErr; 408 | try { 409 | istanbul.writeReports({ reporters: ['not-a-valid-reporter'] }); 410 | } catch (err) { 411 | actualErr = err; 412 | } 413 | assert.equal(actualErr.plugin, 'gulp-coffee-istanbul'); 414 | }); 415 | }); 416 | --------------------------------------------------------------------------------