├── test ├── scenarios │ ├── requireArrayOption │ │ ├── require │ │ │ ├── common4.js │ │ │ ├── common3.js │ │ │ ├── common1.js │ │ │ └── common2.js │ │ ├── test.js │ │ └── Gruntfile.js │ ├── requireFailure │ │ ├── test.js │ │ └── Gruntfile.js │ ├── requireCompilersOption │ │ ├── globals.js │ │ ├── lib.coffee │ │ ├── test.coffee │ │ └── Gruntfile.coffee │ ├── requireOption │ │ ├── require │ │ │ └── common.js │ │ ├── test.js │ │ └── Gruntfile.js │ ├── requireOptionCLI │ │ ├── require │ │ │ └── common.js │ │ ├── test.js │ │ └── Gruntfile.js │ ├── only │ │ ├── test2.js │ │ ├── test1.js │ │ └── Gruntfile.js │ ├── tests │ │ ├── test1.js │ │ ├── test2.js │ │ └── Gruntfile.js │ ├── colorsOption │ │ ├── test.js │ │ └── Gruntfile.js │ ├── growlOption │ │ ├── test1.js │ │ ├── test2.js │ │ └── Gruntfile.js │ ├── quietOption │ │ ├── test1.js │ │ ├── test2.js │ │ └── Gruntfile.js │ ├── uiOption │ │ ├── test1.js │ │ ├── test2.js │ │ └── Gruntfile.js │ ├── clearRequireCacheAndRequireOptions │ │ ├── require │ │ │ └── common.js │ │ ├── first.js │ │ ├── second.js │ │ └── Gruntfile.js │ ├── destinationFile │ │ ├── test1.js │ │ ├── test2.js │ │ └── Gruntfile.js │ ├── reporterOption │ │ ├── test1.js │ │ ├── test2.js │ │ └── Gruntfile.js │ ├── xunitReporter │ │ ├── test.js │ │ └── Gruntfile.js │ ├── testsExpand │ │ ├── subfolder │ │ │ ├── test1.js │ │ │ └── test2.js │ │ └── Gruntfile.js │ ├── asyncOnlyOption │ │ ├── test.js │ │ └── Gruntfile.js │ ├── destinationFileCreateDirectories │ │ ├── test1.js │ │ ├── test2.js │ │ └── Gruntfile.js │ ├── uiOptionCustom │ │ ├── test.js │ │ ├── Gruntfile.js │ │ └── example-ui.js │ ├── globalsOption │ │ ├── test.js │ │ └── Gruntfile.js │ ├── reporterOptions │ │ ├── test.js │ │ └── Gruntfile.js │ ├── ignoreLeaksOption │ │ ├── test.js │ │ └── Gruntfile.js │ ├── testFailure │ │ ├── test.js │ │ └── Gruntfile.js │ ├── testFailureWithNoFail │ │ ├── test.js │ │ └── Gruntfile.js │ ├── gruntEnvIntegration │ │ ├── test.js │ │ └── Gruntfile.js │ ├── timeoutOption │ │ ├── test.js │ │ └── Gruntfile.js │ ├── grepOption │ │ ├── test.js │ │ └── Gruntfile.js │ ├── invertOption │ │ ├── test.js │ │ └── Gruntfile.js │ ├── asyncTestFailure │ │ ├── test.js │ │ └── Gruntfile.js │ ├── requireSingleton │ │ ├── test2.js │ │ ├── require │ │ │ └── singleton.js │ │ ├── Gruntfile.js │ │ └── test1.js │ ├── connectFailure │ │ ├── test.js │ │ └── Gruntfile.js │ ├── asyncFailureWithBefore │ │ ├── Gruntfile.js │ │ └── test.js │ ├── clearCacheFilterOption │ │ ├── teston.js │ │ ├── testoff.js │ │ └── Gruntfile.js │ ├── clearRequireCacheOption │ │ ├── testoff.js │ │ ├── teston.js │ │ └── Gruntfile.js │ └── noFiles │ │ └── Gruntfile.js ├── helpers │ └── grunt-shared.js └── tasks │ └── grunt-mocha-test.js ├── .travis.yml ├── .gitignore ├── LICENSE-MIT ├── package.json ├── tasks ├── lib │ └── MochaWrapper.js └── mocha-test.js ├── Gruntfile.js └── README.md /test/scenarios/requireArrayOption/require/common4.js: -------------------------------------------------------------------------------- 1 | module.exports = ' '; 2 | -------------------------------------------------------------------------------- /test/scenarios/requireFailure/test.js: -------------------------------------------------------------------------------- 1 | var doesNotExist = require('doesNotExist'); 2 | -------------------------------------------------------------------------------- /test/scenarios/requireCompilersOption/globals.js: -------------------------------------------------------------------------------- 1 | /*global testVar:true */ 2 | testVar = 'test'; -------------------------------------------------------------------------------- /test/scenarios/requireOption/require/common.js: -------------------------------------------------------------------------------- 1 | /*global testVar:true */ 2 | testVar = 'hello'; 3 | -------------------------------------------------------------------------------- /test/scenarios/requireArrayOption/require/common3.js: -------------------------------------------------------------------------------- 1 | /*global testVar3:true */ 2 | testVar3 = '!'; 3 | -------------------------------------------------------------------------------- /test/scenarios/requireOptionCLI/require/common.js: -------------------------------------------------------------------------------- 1 | /*global testVar:true */ 2 | testVar = 'hello'; 3 | -------------------------------------------------------------------------------- /test/scenarios/requireArrayOption/require/common1.js: -------------------------------------------------------------------------------- 1 | /*global testVar1:true */ 2 | testVar1 = 'hello'; 3 | -------------------------------------------------------------------------------- /test/scenarios/requireArrayOption/require/common2.js: -------------------------------------------------------------------------------- 1 | /*global testVar2:true */ 2 | testVar2 = 'world'; 3 | -------------------------------------------------------------------------------- /test/scenarios/only/test2.js: -------------------------------------------------------------------------------- 1 | describe('test2', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/tests/test1.js: -------------------------------------------------------------------------------- 1 | describe('test1', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/tests/test2.js: -------------------------------------------------------------------------------- 1 | describe('test2', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/colorsOption/test.js: -------------------------------------------------------------------------------- 1 | describe('test', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/growlOption/test1.js: -------------------------------------------------------------------------------- 1 | describe('test1', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/growlOption/test2.js: -------------------------------------------------------------------------------- 1 | describe('test2', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/quietOption/test1.js: -------------------------------------------------------------------------------- 1 | describe('test1', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/quietOption/test2.js: -------------------------------------------------------------------------------- 1 | describe('test2', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/uiOption/test1.js: -------------------------------------------------------------------------------- 1 | suite('test1', function(){ 2 | test('should be ok', function(){ 3 | }); 4 | }); 5 | -------------------------------------------------------------------------------- /test/scenarios/uiOption/test2.js: -------------------------------------------------------------------------------- 1 | suite('test2', function(){ 2 | test('should be ok', function(){ 3 | }); 4 | }); 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "lts/*" 4 | install: 5 | - npm install 6 | script: "npm run-script ci" 7 | -------------------------------------------------------------------------------- /test/scenarios/clearRequireCacheAndRequireOptions/require/common.js: -------------------------------------------------------------------------------- 1 | /*global testVar:true */ 2 | global.testVar = 'hello'; 3 | -------------------------------------------------------------------------------- /test/scenarios/destinationFile/test1.js: -------------------------------------------------------------------------------- 1 | describe('test1', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/destinationFile/test2.js: -------------------------------------------------------------------------------- 1 | describe('test2', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/only/test1.js: -------------------------------------------------------------------------------- 1 | describe('test1', function() { 2 | it.only('should be ok', function() { 3 | }); 4 | }); 5 | -------------------------------------------------------------------------------- /test/scenarios/reporterOption/test1.js: -------------------------------------------------------------------------------- 1 | describe('test1', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/reporterOption/test2.js: -------------------------------------------------------------------------------- 1 | describe('test2', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/xunitReporter/test.js: -------------------------------------------------------------------------------- 1 | describe('test', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); 5 | -------------------------------------------------------------------------------- /test/scenarios/testsExpand/subfolder/test1.js: -------------------------------------------------------------------------------- 1 | describe('test1', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/testsExpand/subfolder/test2.js: -------------------------------------------------------------------------------- 1 | describe('test2', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/asyncOnlyOption/test.js: -------------------------------------------------------------------------------- 1 | describe('test', function() { 2 | it('is not asynchronous', function() { 3 | }); 4 | }); 5 | -------------------------------------------------------------------------------- /test/scenarios/destinationFileCreateDirectories/test1.js: -------------------------------------------------------------------------------- 1 | describe('test1', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/destinationFileCreateDirectories/test2.js: -------------------------------------------------------------------------------- 1 | describe('test2', function() { 2 | it('should be ok', function() { 3 | }); 4 | }); -------------------------------------------------------------------------------- /test/scenarios/uiOptionCustom/test.js: -------------------------------------------------------------------------------- 1 | /* global check */ 2 | /* global test */ 3 | test(function (done){ 4 | check("a", "a"); 5 | done(); 6 | }); -------------------------------------------------------------------------------- /test/scenarios/requireCompilersOption/lib.coffee: -------------------------------------------------------------------------------- 1 | module.exports = class Test 2 | constructor: (@name) -> 3 | 4 | sayHello: => 5 | 'Hello, ' + @name -------------------------------------------------------------------------------- /test/scenarios/globalsOption/test.js: -------------------------------------------------------------------------------- 1 | /*global leak:true*/ 2 | 3 | describe('test', function() { 4 | it('should leak', function() { 5 | leak = 'this is a leak'; 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /test/scenarios/reporterOptions/test.js: -------------------------------------------------------------------------------- 1 | describe('test', function() { 2 | for (var i = 0; i < 1000; ++i) { 3 | it('should be ok ' + i, function() { 4 | }); 5 | } 6 | }); 7 | -------------------------------------------------------------------------------- /test/scenarios/ignoreLeaksOption/test.js: -------------------------------------------------------------------------------- 1 | /*global leak:true*/ 2 | 3 | describe('test', function() { 4 | it('should leak', function() { 5 | leak = 'this is a leak'; 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /test/scenarios/testFailure/test.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | 3 | describe('test', function() { 4 | it('should fail', function() { 5 | expect(true).to.equal(false); 6 | }); 7 | }); -------------------------------------------------------------------------------- /test/scenarios/testFailureWithNoFail/test.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | 3 | describe('test', function() { 4 | it('should fail', function() { 5 | expect(true).to.equal(false); 6 | }); 7 | }); -------------------------------------------------------------------------------- /test/scenarios/gruntEnvIntegration/test.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | 3 | describe('test', function() { 4 | it('should be ok', function() { 5 | expect(process.env.TEST).to.equal('this is a test'); 6 | }); 7 | }); -------------------------------------------------------------------------------- /test/scenarios/requireOption/test.js: -------------------------------------------------------------------------------- 1 | /*global testVar:false*/ 2 | 3 | var expect = require('chai').expect; 4 | 5 | describe('test', function() { 6 | it('should pass', function() { 7 | expect(testVar).to.equal('hello'); 8 | }); 9 | }); -------------------------------------------------------------------------------- /test/scenarios/timeoutOption/test.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | 3 | describe('test', function() { 4 | it('should timeout', function(done) { 5 | setTimeout(function() { 6 | done(); 7 | }, 1000); 8 | }); 9 | }); -------------------------------------------------------------------------------- /test/scenarios/requireOptionCLI/test.js: -------------------------------------------------------------------------------- 1 | /*global testVar:false*/ 2 | 3 | var expect = require('chai').expect; 4 | 5 | describe('test', function() { 6 | it('should pass', function() { 7 | expect(testVar).to.equal('hello'); 8 | }); 9 | }); -------------------------------------------------------------------------------- /test/scenarios/grepOption/test.js: -------------------------------------------------------------------------------- 1 | describe('tests that match grep', function() { 2 | it('should pass', function() { 3 | }); 4 | }); 5 | 6 | describe('tests that don\'t match grep', function() { 7 | it('should pass', function() { 8 | }); 9 | }); -------------------------------------------------------------------------------- /test/scenarios/invertOption/test.js: -------------------------------------------------------------------------------- 1 | describe('tests that match grep', function() { 2 | it('should pass', function() { 3 | }); 4 | }); 5 | 6 | describe('tests that don\'t match grep', function() { 7 | it('should pass', function() { 8 | }); 9 | }); -------------------------------------------------------------------------------- /test/scenarios/asyncTestFailure/test.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | 3 | describe('Asynchronous test', function() { 4 | it('should fail', function(done) { 5 | process.nextTick(function () { 6 | expect(true).to.equal(false); 7 | done(); 8 | }); 9 | }); 10 | }); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | 5 | # WebStorm Stuff 6 | .idea 7 | 8 | # coverage stuff 9 | lib-cov 10 | /reports 11 | 12 | # test stuff 13 | /test/scenarios/destinationFile/output 14 | /test/scenarios/quietOption/output 15 | /test/scenarios/reporterOptions/output 16 | -------------------------------------------------------------------------------- /test/scenarios/requireSingleton/test2.js: -------------------------------------------------------------------------------- 1 | /* global singleton:false */ 2 | 3 | var expect = require('chai').expect; 4 | 5 | describe('test2', function() { 6 | it('should pass', function () { 7 | var hello = singleton.getInstance('hello'); 8 | expect(hello.world).to.equal('world'); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /test/scenarios/only/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec' 7 | }, 8 | all: { 9 | src: ['*.js'] 10 | } 11 | } 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /test/scenarios/tests/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec' 7 | }, 8 | all: { 9 | src: ['*.js'] 10 | } 11 | } 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /test/scenarios/connectFailure/test.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | var net = require('net'); 3 | 4 | describe('Connection test', function() { 5 | it('should fail', function(done) { 6 | net.connect({ 7 | port: 10000, 8 | host: 'doesnotexist' 9 | }, function () { 10 | done(); 11 | }); 12 | }); 13 | }); -------------------------------------------------------------------------------- /test/scenarios/requireSingleton/require/singleton.js: -------------------------------------------------------------------------------- 1 | /* global singleton:true */ 2 | 3 | var privateKeys = new Object(null); 4 | singleton = new Object(null); 5 | singleton.getInstance = function(key) { 6 | if (!privateKeys.hasOwnProperty(key)) { 7 | privateKeys[key] = new Object(null); 8 | } 9 | return privateKeys[key]; 10 | }; 11 | -------------------------------------------------------------------------------- /test/scenarios/testFailure/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec' 7 | }, 8 | all: { 9 | src: ['*.js'] 10 | } 11 | } 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /test/scenarios/asyncTestFailure/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec' 7 | }, 8 | all: { 9 | src: ['*.js'] 10 | } 11 | } 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /test/scenarios/connectFailure/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec' 7 | }, 8 | all: { 9 | src: ['*.js'] 10 | } 11 | } 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /test/scenarios/reporterOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'doc' 7 | }, 8 | all: { 9 | src: ['*.js'] 10 | } 11 | } 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /test/scenarios/requireCompilersOption/test.coffee: -------------------------------------------------------------------------------- 1 | expect = require('chai').expect 2 | Test = require './lib' 3 | 4 | describe 'test coffee-script', => 5 | it 'should pass', => 6 | test = new Test 'Peter' 7 | expect(test.sayHello()).to.equal 'Hello, Peter' 8 | expect(testVar).to.equal 'test' 9 | expect 1 10 | .to.equal 1 11 | -------------------------------------------------------------------------------- /test/scenarios/requireFailure/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec' 7 | }, 8 | all: { 9 | src: ['*.js'] 10 | } 11 | } 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /test/scenarios/requireOptionCLI/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec' 7 | }, 8 | all: { 9 | src: ['*.js'] 10 | } 11 | } 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /test/scenarios/xunitReporter/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'xunit' 7 | }, 8 | all: { 9 | src: ['*.js'] 10 | } 11 | } 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /test/scenarios/asyncFailureWithBefore/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec' 7 | }, 8 | all: { 9 | src: ['*.js'] 10 | } 11 | } 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /test/scenarios/clearCacheFilterOption/teston.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | var path = require('path'); 3 | 4 | describe('check content of require cache contain tasks/mocha.js', function() { 5 | it('should pass', function() { 6 | expect(require.cache).to.have.property(path.resolve(__dirname, '../../../tasks/mocha-test.js')); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /test/scenarios/clearRequireCacheOption/testoff.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | var path = require('path'); 3 | 4 | describe('check content of require cache contain tasks/mocha.js', function() { 5 | it('should pass', function() { 6 | expect(require.cache).to.have.property(path.resolve(__dirname, '../../../tasks/mocha-test.js')); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /test/scenarios/uiOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec', 7 | ui: 'tdd' 8 | }, 9 | all: { 10 | src: ['*.js'] 11 | } 12 | } 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /test/scenarios/clearCacheFilterOption/testoff.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | var path = require('path'); 3 | 4 | describe('check content of require cache does not contain tasks/mocha.js', function() { 5 | it('should pass', function() { 6 | expect(require.cache).not.to.have.property(path.resolve(__dirname, '../../../tasks/mocha-test.js')); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /test/scenarios/clearRequireCacheOption/teston.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | var path = require('path'); 3 | 4 | describe('check content of require cache does not contain tasks/mocha.js', function() { 5 | it('should pass', function() { 6 | expect(require.cache).not.to.have.property(path.resolve(__dirname, '../../../tasks/mocha-test.js')); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /test/scenarios/growlOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec', 7 | growl: true 8 | }, 9 | all: { 10 | src: ['*.js'] 11 | } 12 | } 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /test/scenarios/colorsOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec', 7 | useColors: true 8 | }, 9 | all: { 10 | src: ['*.js'] 11 | } 12 | } 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /test/scenarios/timeoutOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec', 7 | timeout: 500 8 | }, 9 | all: { 10 | src: ['*.js'] 11 | } 12 | } 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /test/scenarios/uiOptionCustom/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | test:{ 6 | options:{reporter:"spec", require:__dirname+"/example-ui.js", ui:"example-ui"}, 7 | src:"test.js" 8 | } 9 | }, 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /test/scenarios/asyncOnlyOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec', 7 | asyncOnly: true 8 | }, 9 | all: { 10 | src: ['*.js'] 11 | } 12 | } 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /test/scenarios/destinationFile/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec', 7 | captureFile: 'output' 8 | }, 9 | all: { 10 | src: ['*.js'] 11 | } 12 | } 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /test/scenarios/ignoreLeaksOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec', 7 | ignoreLeaks: false 8 | }, 9 | all: { 10 | src: ['*.js'] 11 | } 12 | } 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /test/scenarios/testFailureWithNoFail/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | noFail: true, 7 | reporter: 'spec' 8 | }, 9 | all: { 10 | src: ['*.js'] 11 | } 12 | } 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /test/scenarios/grepOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec', 7 | grep: 'tests that match grep' 8 | }, 9 | all: { 10 | src: ['*.js'] 11 | } 12 | } 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /test/scenarios/clearRequireCacheAndRequireOptions/first.js: -------------------------------------------------------------------------------- 1 | /*global testVar:true*/ 2 | 3 | var expect = require('chai').expect; 4 | 5 | describe('test', function() { 6 | it('should pass', function() { 7 | expect(testVar).to.equal('hello'); 8 | }); 9 | it('should also pass', function() { 10 | testVar = 'goodbye'; 11 | expect(testVar).to.equal('goodbye'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /test/scenarios/clearRequireCacheAndRequireOptions/second.js: -------------------------------------------------------------------------------- 1 | /*global testVar:true*/ 2 | 3 | var expect = require('chai').expect; 4 | 5 | describe('test', function() { 6 | it('should pass', function() { 7 | expect(testVar).to.equal('hello'); 8 | }); 9 | it('should also pass', function() { 10 | testVar = 'goodbye'; 11 | expect(testVar).to.equal('goodbye'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /test/scenarios/requireCompilersOption/Gruntfile.coffee: -------------------------------------------------------------------------------- 1 | gruntShared = require '../../helpers/grunt-shared' 2 | module.exports = (grunt) -> 3 | gruntShared(grunt, __dirname, 4 | mochaTest: 5 | options: 6 | reporter: 'spec', 7 | require: [ 8 | 'coffee-script/register', 9 | './globals' 10 | ] 11 | all: 12 | src: ['test.coffee'] 13 | ) 14 | -------------------------------------------------------------------------------- /test/scenarios/testsExpand/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec' 7 | }, 8 | all: { 9 | expand: true, 10 | cwd: 'subfolder', 11 | src: ['*.js'] 12 | } 13 | } 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /test/scenarios/destinationFileCreateDirectories/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec', 7 | captureFile: 'reports/output' 8 | }, 9 | all: { 10 | src: ['*.js'] 11 | } 12 | } 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /test/scenarios/requireSingleton/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec', 7 | require: 'require/singleton' 8 | }, 9 | all: { 10 | src: ['test1.js', 'test2.js'] 11 | } 12 | } 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /test/scenarios/globalsOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec', 7 | ignoreLeaks: false, 8 | globals: ['leak'] 9 | }, 10 | all: { 11 | src: ['*.js'] 12 | } 13 | } 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /test/scenarios/invertOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec', 7 | grep: 'tests that match grep', 8 | invert: true 9 | }, 10 | all: { 11 | src: ['*.js'] 12 | } 13 | } 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /test/scenarios/reporterOptions/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'xunit', 7 | reporterOptions: { 8 | output: 'output' 9 | } 10 | }, 11 | all: { 12 | src: ['*.js'] 13 | } 14 | } 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /test/scenarios/requireOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec' 7 | }, 8 | all: { 9 | src: ['*.js'], 10 | options: { 11 | require: 'require/common' 12 | } 13 | } 14 | } 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /test/scenarios/requireSingleton/test1.js: -------------------------------------------------------------------------------- 1 | /* global singleton:false */ 2 | 3 | var expect = require('chai').expect; 4 | 5 | describe('test1', function() { 6 | before(function () { 7 | var hello = singleton.getInstance('hello'); 8 | hello.world = 'world'; 9 | }); 10 | 11 | it('should pass', function () { 12 | var hello = singleton.getInstance('hello'); 13 | expect(hello.world).to.equal('world'); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test/scenarios/quietOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec' 7 | }, 8 | all: { 9 | options: { 10 | quiet: true, 11 | captureFile: 'output' 12 | }, 13 | src: ['*.js'] 14 | } 15 | } 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /test/scenarios/noFiles/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec' 7 | }, 8 | all: { 9 | options: { 10 | quiet: true, 11 | captureFile: 'output' 12 | }, 13 | src: ['nothingInHere/*.js'] 14 | } 15 | } 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /test/scenarios/requireArrayOption/test.js: -------------------------------------------------------------------------------- 1 | /*global testVar1:false, testVar2:false, testVar3:false, testVar4:false, testVar5:false*/ 2 | 3 | var expect = require('chai').expect; 4 | 5 | describe('test', function() { 6 | it('should pass', function() { 7 | expect(testVar1).to.equal('hello'); 8 | expect(testVar2).to.equal('world'); 9 | expect(testVar3).to.equal('!'); 10 | expect(testVar4).to.equal(' '); 11 | expect(testVar5).to.equal(':)'); 12 | }); 13 | }); -------------------------------------------------------------------------------- /test/scenarios/uiOptionCustom/example-ui.js: -------------------------------------------------------------------------------- 1 | var Mocha = module.parent.require("mocha"); 2 | module.exports = function (suite){ 3 | suite.on('pre-require', function(context){ 4 | context.test = function (fn){ 5 | suite.addTest(new Mocha.Test("stupid test", fn)); 6 | }; 7 | context.check = function (a, b){ 8 | if(a !== b){ 9 | throw ("Error "+ a + "!=" + b); 10 | } 11 | }; 12 | }); 13 | }; 14 | Mocha.interfaces["example-ui"] = module.exports; -------------------------------------------------------------------------------- /test/scenarios/clearRequireCacheAndRequireOptions/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec', 7 | require: 'require/common', 8 | clearRequireCache: true 9 | }, 10 | first: { 11 | src: ['first.js'] 12 | }, 13 | second: { 14 | src: ['second.js'] 15 | } 16 | } 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /test/scenarios/gruntEnvIntegration/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | env: { 5 | test: { 6 | TEST: 'this is a test' 7 | } 8 | }, 9 | mochaTest: { 10 | options: { 11 | reporter: 'spec' 12 | }, 13 | all: { 14 | src: ['*.js'] 15 | } 16 | } 17 | }, ['env', 'mochaTest'], ['../../../../node_modules/grunt-env/tasks']); 18 | }; 19 | -------------------------------------------------------------------------------- /test/scenarios/clearRequireCacheOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec' 7 | }, 8 | on: { 9 | options: { 10 | clearRequireCache: true 11 | }, 12 | src: ['teston.js'] 13 | }, 14 | off: { 15 | options: { 16 | clearRequireCache: false 17 | }, 18 | src: ['testoff.js'] 19 | } 20 | } 21 | }, ['mochaTest:off', 'mochaTest:on']); 22 | }; 23 | -------------------------------------------------------------------------------- /test/scenarios/requireArrayOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*global testVar4:true, testVar5:true*/ 2 | 3 | var gruntShared = require('../../helpers/grunt-shared'); 4 | module.exports = function(grunt) { 5 | gruntShared(grunt, __dirname, { 6 | mochaTest: { 7 | options: { 8 | reporter: 'spec', 9 | require: [ 10 | 'require/common1', 11 | 'require/common2', 12 | 'require/common3', 13 | function(){ testVar4=require('./require/common4'); }, 14 | function(){ testVar5=':)'; } 15 | ] 16 | }, 17 | all: { 18 | src: ['*.js'] 19 | } 20 | } 21 | }); 22 | }; 23 | -------------------------------------------------------------------------------- /test/scenarios/clearCacheFilterOption/Gruntfile.js: -------------------------------------------------------------------------------- 1 | var gruntShared = require('../../helpers/grunt-shared'); 2 | module.exports = function(grunt) { 3 | gruntShared(grunt, __dirname, { 4 | mochaTest: { 5 | options: { 6 | reporter: 'spec' 7 | }, 8 | on: { 9 | options: { 10 | clearRequireCache: true, 11 | clearCacheFilter: (key) => /mocha-test.js/.exec(key) 12 | }, 13 | src: ['teston.js'] 14 | }, 15 | off: { 16 | options: { 17 | clearRequireCache: true 18 | }, 19 | src: ['testoff.js'] 20 | } 21 | } 22 | }, ['mochaTest:on', 'mochaTest:off']); 23 | }; 24 | -------------------------------------------------------------------------------- /test/helpers/grunt-shared.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = function(grunt, testDir, config, tasks, modules) { 4 | tasks = tasks || ['mochaTest']; 5 | modules = modules || []; 6 | 7 | tasks = ['continue:on'].concat(tasks); 8 | tasks = tasks.concat([ 9 | 'continue:off', 10 | 'storeCoverage', 11 | 'continue:fail-on-warning' 12 | ]); 13 | 14 | // Add our tasks. 15 | grunt.loadTasks('../../../tasks'); 16 | grunt.loadTasks('../../../../node_modules/grunt-istanbul/tasks'); 17 | grunt.loadTasks('../../../../node_modules/grunt-continue/tasks'); 18 | modules.forEach(function(mod) { 19 | grunt.loadTasks(mod); 20 | }); 21 | 22 | 23 | Object.assign(config, { 24 | storeCoverage: { 25 | options: { 26 | dir: path.resolve(testDir, `../../../../reports/scenarios/${path.basename(testDir)}`) 27 | } 28 | } 29 | }); 30 | 31 | // Project configuration. 32 | grunt.initConfig(config); 33 | 34 | // Default task. 35 | grunt.registerTask('default', tasks); 36 | }; 37 | -------------------------------------------------------------------------------- /test/scenarios/asyncFailureWithBefore/test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var chai = require('chai'); 4 | var expect = chai.expect; 5 | var http = require('http'); 6 | 7 | 8 | // Create an HTTP tunneling proxy 9 | var proxy = http.createServer(function (req, res) { 10 | res.writeHead(200, {'Content-Type': 'text/plain'}); 11 | res.end('okay'); 12 | }); 13 | 14 | before(function(done){ 15 | proxy.listen(1337, '127.0.0.1', done); 16 | }); 17 | 18 | describe('async tests', function () { 19 | it('first passes', function (done) { 20 | process.nextTick(function () { 21 | expect(true).to.equal(true); 22 | done(); 23 | }); 24 | }); 25 | it('second fails', function (done) { 26 | process.nextTick(function () { 27 | expect(true).to.equal(false); 28 | done(); 29 | }); 30 | }); 31 | it('third passes', function (done) { 32 | process.nextTick(function () { 33 | expect(true).to.equal(true); 34 | done(); 35 | }); 36 | }); 37 | }); -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Peter Halliday 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grunt-mocha-test", 3 | "description": "A grunt task for running server side mocha tests", 4 | "version": "0.13.3", 5 | "homepage": "https://github.com/pghalliday/grunt-mocha-test", 6 | "author": { 7 | "name": "Peter Halliday", 8 | "email": "pghalliday@gmail.com", 9 | "url": "http://pghalliday.github.io/" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/pghalliday/grunt-mocha-test.git" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/pghalliday/grunt-mocha-test/issues" 17 | }, 18 | "license": "MIT", 19 | "engines": { 20 | "node": ">= 0.10.4" 21 | }, 22 | "scripts": { 23 | "test": "grunt", 24 | "ci": "grunt ci" 25 | }, 26 | "config": { 27 | "travis-cov": { 28 | "threshold": 100 29 | } 30 | }, 31 | "dependencies": { 32 | "hooker": "^0.2.3", 33 | "mkdirp": "^0.5.0" 34 | }, 35 | "peerDependencies": { 36 | "mocha": ">=1.20.0" 37 | }, 38 | "devDependencies": { 39 | "chai": "^3.5.0", 40 | "coffee-script": "^1.10.0", 41 | "grunt": "^1.0.1", 42 | "grunt-cli": "^1.2.0", 43 | "grunt-continue": "^0.1.0", 44 | "grunt-contrib-clean": "^1.0.0", 45 | "grunt-contrib-copy": "^1.0.0", 46 | "grunt-contrib-jshint": "^1.0.0", 47 | "grunt-coveralls": "^1.0.1", 48 | "grunt-env": "^0.4.4", 49 | "grunt-istanbul": "^0.7.1", 50 | "grunt-istanbul-coverage": "^0.1.4", 51 | "mocha": "^3.0.2", 52 | "rimraf": "^2.5.0" 53 | }, 54 | "keywords": [ 55 | "gruntplugin", 56 | "mocha", 57 | "test" 58 | ], 59 | "files": [ 60 | "tasks", 61 | "LICENSE-MIT" 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /tasks/lib/MochaWrapper.js: -------------------------------------------------------------------------------- 1 | var domain = require('domain'); 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | var Mocha = require('mocha'); 5 | 6 | function MochaWrapper(params) { 7 | // If require option is specified then require that file. 8 | // This code has been adapted from the treatment of the require 9 | // option in the mocha source (bin/_mocha) 10 | var cwd = process.cwd(); 11 | var join = path.join; 12 | var resolve = path.resolve; 13 | var exists = fs.existsSync; 14 | module.paths.push(cwd, join(cwd, 'node_modules')); 15 | if (params.options && params.options.require) { 16 | var mods = params.options.require instanceof Array ? params.options.require : [params.options.require]; 17 | mods.forEach(function(mod) { 18 | if (typeof mod === 'string') { 19 | var abs = exists(mod) || exists(mod + '.js'); 20 | if (abs) { 21 | mod = resolve(mod); 22 | } 23 | require(mod); 24 | } else if (typeof mod === 'function') { 25 | mod(); 26 | } 27 | }); 28 | } 29 | 30 | var mocha = new Mocha(params.options); 31 | 32 | var filterFunc = params.options.clearCacheFilter; 33 | if (params.options.clearRequireCache === true) { 34 | Object.keys(require.cache).forEach(function (key) { 35 | if (typeof filterFunc !== 'function' || !filterFunc(key)) { 36 | delete require.cache[key]; 37 | } 38 | }); 39 | } 40 | 41 | params.files.forEach(function(file) { 42 | file.src.forEach(mocha.addFile.bind(mocha)); 43 | }); 44 | 45 | this.run = function(callback) { 46 | try { 47 | mocha.run(function(failureCount) { 48 | callback(null, failureCount); 49 | }); 50 | } catch (error) { 51 | // catch synchronous (uncaught) exceptions thrown as a result 52 | // of loading the test files so that they can be reported with 53 | // better details 54 | callback(error); 55 | } 56 | }; 57 | } 58 | module.exports = MochaWrapper; 59 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.loadNpmTasks('grunt-contrib-jshint'); 4 | grunt.loadNpmTasks('grunt-contrib-clean'); 5 | grunt.loadNpmTasks('grunt-contrib-copy'); 6 | grunt.loadNpmTasks('grunt-istanbul'); 7 | grunt.loadNpmTasks('grunt-istanbul-coverage'); 8 | grunt.loadNpmTasks('grunt-coveralls'); 9 | 10 | // Add our custom tasks. 11 | grunt.loadTasks('tasks'); 12 | 13 | // Project configuration. 14 | grunt.initConfig({ 15 | jshint: { 16 | options: { 17 | curly: true, 18 | eqeqeq: true, 19 | immed: true, 20 | latedef: true, 21 | newcap: true, 22 | noarg: true, 23 | sub: true, 24 | undef: true, 25 | boss: true, 26 | eqnull: true, 27 | node: true, 28 | strict: false, 29 | mocha: true, 30 | esversion: 6 31 | }, 32 | all: { 33 | src: ['grunt.js', 'tasks/**/*.js', 'test/**/*.js'] 34 | } 35 | }, 36 | clean: { 37 | coverage: { 38 | src: ['lib-cov/'] 39 | }, 40 | reports: { 41 | src: ['reports/'] 42 | } 43 | }, 44 | copy: { 45 | test: { 46 | src: ['test/**'], 47 | dest: 'lib-cov/' 48 | } 49 | }, 50 | instrument: { 51 | files: 'tasks/**/*.js', 52 | options: { 53 | lazy: true, 54 | basePath: 'lib-cov/' 55 | } 56 | }, 57 | mochaTest: { 58 | spec: { 59 | options: { 60 | reporter: 'spec', 61 | // tests are quite slow as they spawn node processes 62 | timeout: 10000 63 | }, 64 | src: ['lib-cov/test/tasks/**/*.js'] 65 | }, 66 | }, 67 | makeReport: { 68 | src: 'reports/**/*.json', 69 | options: { 70 | type: 'lcov', 71 | dir: 'reports', 72 | print: 'detail' 73 | } 74 | }, 75 | coverage: { 76 | default: { 77 | options: { 78 | thresholds: { 79 | 'statements': 100, 80 | 'branches': 95, 81 | 'lines': 100, 82 | 'functions': 100 83 | }, 84 | dir: 'reports' 85 | } 86 | } 87 | }, 88 | coveralls: { 89 | options: { 90 | force: true 91 | }, 92 | all: { 93 | src: 'reports/lcov.info' 94 | } 95 | } 96 | }); 97 | 98 | // Default task. 99 | grunt.registerTask('build', ['clean', 'instrument', 'copy']); 100 | grunt.registerTask('default', ['jshint', 'build', 'mochaTest', 'makeReport', 'coverage']); 101 | grunt.registerTask('ci', ['default', 'coveralls']); 102 | }; 103 | -------------------------------------------------------------------------------- /tasks/mocha-test.js: -------------------------------------------------------------------------------- 1 | var MochaWrapper = require('./lib/MochaWrapper'); 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | var hooker = require('hooker'); 5 | var mkdirpSync = require('mkdirp').sync; 6 | 7 | module.exports = function(grunt) { 8 | 9 | // Helper to capture task output (adapted from tests for grunt-contrib-jshint) 10 | var capture = function(captureFile, quiet, run, done) { 11 | var fd; 12 | if (captureFile) { 13 | mkdirpSync(path.dirname(captureFile)); 14 | fd = fs.openSync(captureFile, 'w'); 15 | } 16 | // Hook process.stdout.write 17 | hooker.hook(process.stdout, 'write', { 18 | // This gets executed before the original process.stdout.write 19 | pre: function(result) { 20 | // Write result to file if it was opened 21 | if (fd) { 22 | fs.writeSync(fd, result); 23 | } 24 | // Prevent the original process.stdout.write from executing if quiet was specified 25 | if (quiet) { 26 | return hooker.preempt(); 27 | } 28 | } 29 | }); 30 | // Execute the code whose output is to be captured 31 | run(function(error, failureCount) { 32 | // close the file if it was opened 33 | if (fd) { 34 | fs.closeSync(fd); 35 | } 36 | // Restore process.stdout.write to its original value 37 | hooker.unhook(process.stdout, 'write'); 38 | // Actually test the actually-logged stdout string to the expected value 39 | done(error, failureCount); 40 | }); 41 | }; 42 | 43 | grunt.registerMultiTask('mochaTest', 'Run node unit tests with Mocha', function() { 44 | var done = this.async(); 45 | var options = this.options(); 46 | var files = this.files; 47 | 48 | // mocha CLI parameters 49 | var params = ['grep', 'ui', 'reporter', 'timeout', 'invert', 'ignoreLeaks', 'growl', 'globals', 'require', 'colors', 'slow']; 50 | 51 | // for every supplied CLI parameter overwrite task option 52 | params.forEach(function(param) { 53 | options[param] = grunt.option(param) || options[param]; 54 | }); 55 | 56 | // check if there are files to test 57 | if (this.filesSrc.length === 0) { 58 | grunt.log.write('No files to check...'); 59 | grunt.log.ok(); 60 | done(true); 61 | return; 62 | } 63 | 64 | // Another hack copied from 65 | // https://github.com/gregrperkins/grunt-mocha-hack 66 | // This time we are preventing grunt handling asynchronous 67 | // exceptions that are thrown when handling asynchronous exceptions 68 | // (I think) 69 | var uncaughtExceptionHandlers = process.listeners('uncaughtException'); 70 | process.removeAllListeners('uncaughtException'); 71 | /* istanbul ignore next */ 72 | var unmanageExceptions = function() { 73 | // Fix for leaking exception handlers suggested by https://github.com/davedoesdev 74 | var names = process.listeners('uncaughtException').map(function (f) { 75 | return f.name; 76 | }); 77 | uncaughtExceptionHandlers.forEach(function (f) { 78 | if (names.indexOf(f.name) < 0) { 79 | process.on('uncaughtException', f); 80 | } 81 | }); 82 | }; 83 | var restore = function() { 84 | unmanageExceptions(); 85 | }; 86 | 87 | capture(options.captureFile, options.quiet, function(complete) { 88 | var mochaWrapper = new MochaWrapper({ 89 | files: files, 90 | options: options 91 | }); 92 | mochaWrapper.run(function(error, failureCount) { 93 | if (error) { 94 | grunt.log.error('Mocha exploded!'); 95 | grunt.log.error(error.stack); 96 | complete(error); 97 | } else { 98 | complete(null, failureCount); 99 | } 100 | }); 101 | }, function(error, failureCount) { 102 | // restore the uncaught exception handlers 103 | restore(); 104 | if (error) { 105 | done(false); 106 | } else if (options.noFail) { 107 | done(true); 108 | } else { 109 | done(failureCount === 0); 110 | } 111 | }); 112 | }); 113 | }; 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # grunt-mocha-test 2 | 3 | [![Build Status](https://travis-ci.org/pghalliday/grunt-mocha-test.svg?branch=master)](https://travis-ci.org/pghalliday/grunt-mocha-test) 4 | [![Coverage Status](https://img.shields.io/coveralls/pghalliday/grunt-mocha-test.svg)](https://coveralls.io/r/pghalliday/grunt-mocha-test?branch=master) 5 | 6 | A grunt task for running server side mocha tests 7 | 8 | ## Usage 9 | 10 | Install next to your project's Gruntfile.js with: 11 | 12 | ``` 13 | npm install grunt-mocha-test --save-dev 14 | ``` 15 | 16 | ### Running tests 17 | 18 | Here is a simple example gruntfile if you just want to run tests 19 | 20 | ```javascript 21 | module.exports = function(grunt) { 22 | 23 | // Add the grunt-mocha-test tasks. 24 | grunt.loadNpmTasks('grunt-mocha-test'); 25 | 26 | grunt.initConfig({ 27 | // Configure a mochaTest task 28 | mochaTest: { 29 | test: { 30 | options: { 31 | reporter: 'spec', 32 | captureFile: 'results.txt', // Optionally capture the reporter output to a file 33 | quiet: false, // Optionally suppress output to standard out (defaults to false) 34 | clearRequireCache: false, // Optionally clear the require cache before running tests (defaults to false) 35 | clearCacheFilter: (key) => true, // Optionally defines which files should keep in cache 36 | noFail: false // Optionally set to not fail on failed tests (will still fail on other errors) 37 | }, 38 | src: ['test/**/*.js'] 39 | } 40 | } 41 | }); 42 | 43 | grunt.registerTask('default', 'mochaTest'); 44 | 45 | }; 46 | ``` 47 | 48 | ### Options 49 | 50 | The following options are specific to `grunt-mocha-test` (ie. not mocha options) 51 | 52 | - `captureFile` - specify a file to capture all output to (will include any output from `console.log`) 53 | - `quiet` - `true` to not output anything to console (normally used with the `captureFile` option when console output would not be human readable) 54 | - `clearRequireCache` - `true` to clear the require cache before each test run (normally used with watch when not spawning each test run in a new `nodejs` context) 55 | - `clearCacheFilter` - `function() { return true/false }` to say which files should remain in cache. Only works with `clearRequireCache` set to `true`) 56 | - `noFail` - `true` to prevent the task failing on failed tests. Useful for CI setups where test reports are processed separately. Will still fail on other errors 57 | 58 | The following mocha options have also been tested (others may have been added since the time of writing through changes to mocha) 59 | 60 | - grep 61 | - ui 62 | - reporter 63 | - timeout 64 | - invert 65 | - ignoreLeaks 66 | - growl 67 | - globals 68 | - bail 69 | - require 70 | - slow 71 | 72 | ### Specifying compilers 73 | 74 | The Mocha `--compilers` option is almost identical to the `--require` option but with additional functionality for use with the Mocha `--watch` mode. As the `--watch` mode is not relevant for this plugin there is no need to implement a separate `compilers` option and actually the `require` option should be used instead. 75 | 76 | The following example shows the use of the CoffeeScript compiler. 77 | 78 | ``` 79 | npm install coffee-script 80 | ``` 81 | 82 | ```javascript 83 | mochaTest: { 84 | test: { 85 | options: { 86 | reporter: 'spec', 87 | require: 'coffee-script/register' 88 | }, 89 | src: ['test/**/*.coffee'] 90 | } 91 | } 92 | ``` 93 | 94 | This is an example for the Babel 6 compiler ([babel must be configured](https://babeljs.io/docs/setup/) separately if you want to use it for something like ES6/ES2015). 95 | 96 | ``` 97 | npm install babel-register 98 | ``` 99 | 100 | ```javascript 101 | mochaTest: { 102 | test: { 103 | options: { 104 | reporter: 'spec', 105 | require: 'babel-register' 106 | }, 107 | src: ['test/**/*.js'] 108 | } 109 | } 110 | ``` 111 | 112 | In order to make this more user friendly, the `require` option can take either a single file/function or an array of files/functions in case you have other globals you wish to require. 113 | 114 | eg. 115 | 116 | ```javascript 117 | mochaTest: { 118 | test: { 119 | options: { 120 | reporter: 'spec', 121 | require: [ 122 | 'coffee-script/register', 123 | './globals.js', 124 | function(){ testVar1=require('./stuff'); }, 125 | function(){ testVar2='other-stuff'; } 126 | ] 127 | }, 128 | src: ['test/**/*.coffee'] 129 | } 130 | } 131 | ``` 132 | 133 | NB. File references for the `require` option can only be used with Javascript files, ie. it is not possible to specify a `./globals.coffee` in the above example. 134 | 135 | ### Specifying a Mocha module 136 | 137 | `grunt-mocha-test` uses npm's `peerDependency` functionality and thus uses whatever version 138 | of `mocha` is installed in your project. If your project does not have `mocha` installed, a compatible 139 | version will automatically be installed when adding `grunt-mocha-test`. 140 | 141 | ### Generating coverage reports 142 | 143 | Here is an example gruntfile that registers 2 test tasks, 1 to run the tests and 1 to generate a coverage report using `blanket.js` to instrument the javascript on the fly. 144 | 145 | ``` 146 | npm install blanket 147 | ``` 148 | 149 | ```javascript 150 | module.exports = function(grunt) { 151 | 152 | grunt.loadNpmTasks('grunt-mocha-test'); 153 | 154 | grunt.initConfig({ 155 | mochaTest: { 156 | test: { 157 | options: { 158 | reporter: 'spec', 159 | // Require blanket wrapper here to instrument other required 160 | // files on the fly. 161 | // 162 | // NB. We cannot require blanket directly as it 163 | // detects that we are not running mocha cli and loads differently. 164 | // 165 | // NNB. As mocha is 'clever' enough to only run the tests once for 166 | // each file the following coverage task does not actually run any 167 | // tests which is why the coverage instrumentation has to be done here 168 | require: 'coverage/blanket' 169 | }, 170 | src: ['test/**/*.js'] 171 | }, 172 | coverage: { 173 | options: { 174 | reporter: 'html-cov', 175 | // use the quiet flag to suppress the mocha console output 176 | quiet: true, 177 | // specify a destination file to capture the mocha 178 | // output (the quiet option does not suppress this) 179 | captureFile: 'coverage.html' 180 | }, 181 | src: ['test/**/*.js'] 182 | } 183 | } 184 | }); 185 | 186 | grunt.registerTask('default', 'mochaTest'); 187 | }; 188 | ``` 189 | 190 | As noted above it is necessary to wrap the blanket require when calling mocha programatically so `coverage/blanket.js` should look something like this. 191 | 192 | ```javascript 193 | var path = require('path'); 194 | var srcDir = path.join(__dirname, '..', 'src'); 195 | 196 | require('blanket')({ 197 | // Only files that match the pattern will be instrumented 198 | pattern: srcDir 199 | }); 200 | ``` 201 | 202 | This will preprocess all `.js` files in the `src` directory. Note that `Blanket` just uses pattern matching so this rework of the paths prevents files in `node_modules` being instrumented too. Also bear in mind using `Blanket` to instrument files on the fly only works if the file is not already in the require cache (this is an odd case but if you can't figure out why a file is not instrumented and the `pattern` looks ok then this may be the cause). 203 | 204 | ### Failing tests if a coverage threshold is not reached 205 | 206 | Building on the previous example, if you wish to have your tests fail if it falls below a certain coverage threshold then I advise using the `travis-cov` reporter 207 | 208 | ``` 209 | npm install travis-cov 210 | ``` 211 | 212 | ```javascript 213 | module.exports = function(grunt) { 214 | 215 | grunt.loadNpmTasks('grunt-mocha-test'); 216 | 217 | grunt.initConfig({ 218 | mochaTest: { 219 | test: { 220 | options: { 221 | reporter: 'spec', 222 | require: 'coverage/blanket' 223 | }, 224 | src: ['test/**/*.js'] 225 | }, 226 | 'html-cov': { 227 | options: { 228 | reporter: 'html-cov', 229 | quiet: true, 230 | captureFile: 'coverage.html' 231 | }, 232 | src: ['test/**/*.js'] 233 | }, 234 | // The travis-cov reporter will fail the tests if the 235 | // coverage falls below the threshold configured in package.json 236 | 'travis-cov': { 237 | options: { 238 | reporter: 'travis-cov' 239 | }, 240 | src: ['test/**/*.js'] 241 | } 242 | } 243 | }); 244 | 245 | grunt.registerTask('default', 'mochaTest'); 246 | }; 247 | ``` 248 | 249 | Don't forget to update `package.json` with options for `travis-cov`, for example: 250 | 251 | ```javascript 252 | ... 253 | 254 | "config": { 255 | "travis-cov": { 256 | // Yes, I like to set the coverage threshold to 100% ;) 257 | "threshold": 100 258 | } 259 | }, 260 | 261 | ... 262 | ``` 263 | 264 | ### Instrumenting source files with coverage data before running tests 265 | 266 | 267 | In most cases it may be more useful to instrument files before running tests. This has the added advantage of creating intermediate files that will match the line numbers reported in exception reports. Here is one possible `Gruntfile.js` that uses the `grunt-blanket` plug in. 268 | 269 | ``` 270 | npm install grunt-contrib-clean 271 | npm install grunt-contrib-copy 272 | npm install grunt-blanket 273 | npm install travis-cov 274 | ``` 275 | 276 | ```javascript 277 | module.exports = function(grunt) { 278 | 279 | grunt.loadNpmTasks('grunt-mocha-test'); 280 | grunt.loadNpmTasks('grunt-contrib-clean'); 281 | grunt.loadNpmTasks('grunt-contrib-copy'); 282 | grunt.loadNpmTasks('grunt-blanket'); 283 | 284 | grunt.initConfig({ 285 | clean: { 286 | coverage: { 287 | src: ['coverage/'] 288 | } 289 | }, 290 | copy: { 291 | coverage: { 292 | src: ['test/**'], 293 | dest: 'coverage/' 294 | } 295 | }, 296 | blanket: { 297 | coverage: { 298 | src: ['src/'], 299 | dest: 'coverage/src/' 300 | } 301 | }, 302 | mochaTest: { 303 | test: { 304 | options: { 305 | reporter: 'spec', 306 | }, 307 | src: ['/coverage/test/**/*.js'] 308 | }, 309 | coverage: { 310 | options: { 311 | reporter: 'html-cov', 312 | quiet: true, 313 | captureFile: 'coverage.html' 314 | }, 315 | src: ['/coverage/test/**/*.js'] 316 | }, 317 | 'travis-cov': { 318 | options: { 319 | reporter: 'travis-cov' 320 | }, 321 | src: ['/coverage/test/**/*.js'] 322 | } 323 | } 324 | }); 325 | 326 | grunt.registerTask('default', ['clean', 'blanket', 'copy', 'mochaTest']); 327 | }; 328 | ``` 329 | 330 | This will delete any previously instrumented files, copy the `test` files to a `coverage` folder and instrument the `src` javascript files to the `coverage` folder. Lastly it runs tests from the `coverage` folder. It's more complicated but often easier to work with. 331 | 332 | ### Running in permanent environments (like watch) 333 | 334 | If you run `grunt-mocha-test` with `grunt-contrib-watch` using the `spawn: false` option, you will notice that the tests only run on the first change. Subsequent changes will result in an empty report with a `0 passing` message. 335 | 336 | This happens because `mocha` loads your tests using `require` resulting in them being added to the require cache. Thus once they have been loaded in a process the subsequent calls to `require` hit the cache without executing the code again. To prevent this from happening, use the `clearRequireCache` option (default value is `false`). 337 | 338 | Here is an example that also demonstrates how to only run changed tests: 339 | 340 | ```javascript 341 | module.exports = function(grunt) { 342 | 343 | grunt.loadNpmTasks('grunt-mocha-test'); 344 | grunt.loadNpmTasks('grunt-contrib-watch'); 345 | 346 | grunt.initConfig({ 347 | mochaTest: { 348 | test: { 349 | options: { 350 | reporter: 'spec', 351 | clearRequireCache: true 352 | }, 353 | src: ['test/**/*.js'] 354 | }, 355 | }, 356 | 357 | watch: { 358 | js: { 359 | options: { 360 | spawn: false, 361 | }, 362 | files: '**/*.js', 363 | tasks: ['default'] 364 | } 365 | } 366 | }); 367 | 368 | // On watch events, if the changed file is a test file then configure mochaTest to only 369 | // run the tests from that file. Otherwise run all the tests 370 | var defaultTestSrc = grunt.config('mochaTest.test.src'); 371 | grunt.event.on('watch', function(action, filepath) { 372 | grunt.config('mochaTest.test.src', defaultTestSrc); 373 | if (filepath.match('test/')) { 374 | grunt.config('mochaTest.test.src', filepath); 375 | } 376 | }); 377 | 378 | grunt.registerTask('default', 'mochaTest'); 379 | }; 380 | ``` 381 | 382 | ### Using node flags 383 | 384 | There are some flags that Mocha supports that are actually Node flags, eg. 385 | 386 | - --debug 387 | - --harmony-generators 388 | 389 | It is currently not possible to set these at runtime when using Mocha as a library and as such cannot be supported by `grunt-mocha-test` without a major refactor (and severe impact on performance as it would involve spawning processes). 390 | 391 | The recommended way of using these flags would be to pass them to node when starting the grunt process. The simplest way to do this would be to leverage the [`scripts`](https://www.npmjs.org/doc/misc/npm-scripts.html) functionality of NPM and `package.json`. 392 | 393 | ``` 394 | ... 395 | }, 396 | "scripts": { 397 | "test": "node --debug --harmony-generators ./node_modules/.bin/grunt test" 398 | } 399 | ... 400 | ``` 401 | 402 | The tests would then be run using 403 | 404 | ``` 405 | npm test 406 | ``` 407 | 408 | Note that this assumes that `grunt-cli` has been installed locally and not globally 409 | 410 | ## Contributing 411 | In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using: 412 | 413 | ``` 414 | npm test 415 | ``` 416 | 417 | ## License 418 | Copyright © 2016 Peter Halliday 419 | Licensed under the MIT license. 420 | 421 | [![Donate Bitcoins](http://i.imgur.com/b5BZsFH.png)](bitcoin:17LtnRG4WxRLYBWzrBoEKP3F7fZx8vcAsK?amount=0.01&label=grunt-mocha-test) 422 | 423 | [17LtnRG4WxRLYBWzrBoEKP3F7fZx8vcAsK](bitcoin:17LtnRG4WxRLYBWzrBoEKP3F7fZx8vcAsK?amount=0.01&label=grunt-mocha-test) 424 | -------------------------------------------------------------------------------- /test/tasks/grunt-mocha-test.js: -------------------------------------------------------------------------------- 1 | /*jshint loopfunc: true */ 2 | 3 | var expect = require('chai').expect; 4 | var path = require('path'); 5 | var fs = require('fs'); 6 | var exec = require('child_process').exec; 7 | var gruntExec = 'node ' + path.resolve('node_modules/grunt-cli/bin/grunt'); 8 | var rimrafSync = require('rimraf').sync; 9 | 10 | var execScenario = function(scenario, callback, options) { 11 | options = options || ''; 12 | var scenarioDir = __dirname + '/../scenarios/' + scenario; 13 | exec(gruntExec + ' ' + options, {cwd: scenarioDir}, callback); 14 | }; 15 | 16 | describe('grunt-mocha-test', function() { 17 | it('should run tests from the supplied files', function(done) { 18 | execScenario('tests', function(error, stdout, stderr) { 19 | expect(stdout).to.match(/test1/); 20 | expect(stdout).to.match(/test2/); 21 | expect(stdout).to.match(/2 passing/); 22 | expect(stdout).to.match(/Done./); 23 | expect(stderr).to.equal(''); 24 | done(); 25 | }); 26 | }); 27 | 28 | it('should run tests from the supplied files respecting `only` specifiers', function(done) { 29 | execScenario('only', function(error, stdout, stderr) { 30 | expect(stdout).to.match(/test1/); 31 | expect(stdout).to.not.match(/test2/); 32 | expect(stdout).to.match(/1 passing/); 33 | expect(stdout).to.match(/Done./); 34 | expect(stderr).to.equal(''); 35 | done(); 36 | }); 37 | }); 38 | 39 | it('should run tests from the supplied files with expand option', function(done) { 40 | execScenario('testsExpand', function(error, stdout, stderr) { 41 | expect(stdout).to.match(/test1/); 42 | expect(stdout).to.match(/test2/); 43 | expect(stdout).to.match(/2 passing/); 44 | expect(stdout).to.match(/Done./); 45 | expect(stderr).to.equal(''); 46 | done(); 47 | }); 48 | }); 49 | 50 | it('should report the number of test failures and exit grunt with an error on failed tests', function(done) { 51 | execScenario('testFailure', function(error, stdout, stderr) { 52 | expect(stdout).to.match(/test/); 53 | expect(stdout).to.match(/Aborted due to warnings./); 54 | expect(stdout).to.match(/1 failing/); 55 | expect(stderr).to.equal(''); 56 | done(); 57 | }); 58 | }); 59 | 60 | it('should exit with code zero to allow structured reporters to differentiate runner failures from assertion failures', function(done) { 61 | execScenario('testFailureWithNoFail', function(error, stdout, stderr) { 62 | expect(stdout).to.match(/test/); 63 | expect(stdout).to.match(/1\) should fail/); 64 | expect(stdout).to.match(/1 failing/); 65 | expect(stdout).to.match(/Done/); 66 | expect(stderr).to.equal(''); 67 | done(); 68 | }); 69 | }); 70 | 71 | it('should cleanly catch asynchronous test failures so that grunt does not exit early', function(done) { 72 | execScenario('asyncTestFailure', function(error, stdout, stderr) { 73 | expect(stdout).to.match(/Asynchronous test/); 74 | expect(stdout).to.match(/Aborted due to warnings./); 75 | expect(stdout).to.match(/1 failing/); 76 | expect(stderr).to.equal(''); 77 | done(); 78 | }); 79 | }); 80 | 81 | it('should cleanly catch and log require exceptions thrown synchronously by Mocha so that grunt does not exit early', function(done) { 82 | execScenario('requireFailure', function(error, stdout, stderr) { 83 | expect(stdout).to.match(/Cannot find module 'doesNotExist/); 84 | expect(stdout).to.match(/test.js/); 85 | expect(stdout).to.match(/Aborted due to warnings./); 86 | expect(stderr).to.equal(''); 87 | done(); 88 | }); 89 | }); 90 | 91 | it('should cleanly catch and log net connect exceptions thrown asynchronously by Mocha so that grunt does not exit early', function(done) { 92 | execScenario('connectFailure', function(error, stdout, stderr) { 93 | expect(stdout).to.match(/Aborted due to warnings./); 94 | expect(stdout).to.match(/1 failing/); 95 | expect(stderr).to.equal(''); 96 | done(); 97 | }); 98 | }); 99 | 100 | it('should cleanly catch and log exceptions thrown asynchronously by tests that have a before that starts an HTTP server', function(done) { 101 | execScenario('asyncFailureWithBefore', function(error, stdout, stderr) { 102 | expect(stdout).to.match(/async tests/); 103 | expect(stdout).to.match(/2 passing/); 104 | expect(stdout).to.match(/Aborted due to warnings./); 105 | expect(stdout).to.match(/1 failing/); 106 | expect(stderr).to.equal(''); 107 | done(); 108 | }); 109 | }); 110 | 111 | it('should support the require option', function(done) { 112 | execScenario('requireOption', function(error, stdout, stderr) { 113 | expect(stdout).to.match(/test/); 114 | expect(stdout).to.match(/1 passing/); 115 | expect(stdout).to.match(/Done./); 116 | expect(stderr).to.equal(''); 117 | done(); 118 | }); 119 | }); 120 | 121 | it('should support the require option via CLI', function(done) { 122 | execScenario('requireOptionCLI', function(error, stdout, stderr) { 123 | expect(stdout).to.match(/test/); 124 | expect(stdout).to.match(/1 passing/); 125 | expect(stdout).to.match(/Done./); 126 | expect(stderr).to.equal(''); 127 | done(); 128 | }, '--require=require/common'); 129 | }); 130 | 131 | it('should support the colors option', function(done) { 132 | execScenario('colorsOption', function(error, stdout, stderr) { 133 | expect(stdout).to.match(/Running "mochaTest:all" \(mochaTest\) task\n\n\u001b\[0m\u001b\[0m\n\u001b\[0m test\u001b\[0m\n \u001b\[32m ✓\u001b\[0m\u001b\[90m should be ok\u001b\[0m\n\n\n\u001b\[92m \u001b\[0m\u001b\[32m 1 passing/); 134 | expect(stderr).to.equal(''); 135 | done(); 136 | }); 137 | }); 138 | 139 | it('should support the require option with arrays', function(done) { 140 | execScenario('requireArrayOption', function(error, stdout, stderr) { 141 | expect(stdout).to.match(/test/); 142 | expect(stdout).to.match(/1 passing/); 143 | expect(stdout).to.match(/Done./); 144 | expect(stderr).to.equal(''); 145 | done(); 146 | }); 147 | }); 148 | 149 | it('should support the require option with complicated globals', function(done) { 150 | execScenario('requireSingleton', function(error, stdout, stderr) { 151 | expect(stdout).to.match(/test1/); 152 | expect(stdout).to.match(/test2/); 153 | expect(stdout).to.match(/2 passing/); 154 | expect(stdout).to.match(/Done./); 155 | expect(stderr).to.equal(''); 156 | done(); 157 | }); 158 | }); 159 | 160 | it('should support the require option with coffee-script', function(done) { 161 | execScenario('requireCompilersOption', function(error, stdout, stderr) { 162 | expect(stdout).to.match(/test coffee-script/); 163 | expect(stdout).to.match(/1 passing/); 164 | expect(stdout).to.match(/Done./); 165 | expect(stderr).to.equal(''); 166 | done(); 167 | }); 168 | }); 169 | 170 | it('should support the clearRequireCacheOption', function(done) { 171 | execScenario('clearRequireCacheOption', function(error, stdout, stderr) { 172 | expect(stdout).to.match(/mochaTest:on/); 173 | expect(stdout).to.match(/mochaTest:off/); 174 | expect(stdout).to.match(/1 passing/); 175 | expect(stdout).not.to.match(/0 passing/); 176 | expect(stdout).not.to.match(/2 passing/); 177 | expect(stdout).to.match(/Done./); 178 | expect(stderr).to.equal(''); 179 | done(); 180 | }); 181 | }); 182 | 183 | it('should support the clearRequireCacheOption with the require option', function(done) { 184 | execScenario('clearRequireCacheAndRequireOptions', function(error, stdout, stderr) { 185 | expect(stdout).to.match(/test/); 186 | expect(stdout).to.match(/2 passing/); 187 | expect(stdout).to.match(/Done./); 188 | expect(stderr).to.equal(''); 189 | done(); 190 | }); 191 | }); 192 | 193 | it('should support the clearCacheFilterOption', function(done) { 194 | execScenario('clearCacheFilterOption', function(error, stdout, stderr) { 195 | expect(stdout).to.match(/mochaTest:on/); 196 | expect(stdout).to.match(/mochaTest:off/); 197 | expect(stdout).to.match(/1 passing/); 198 | expect(stdout).not.to.match(/0 passing/); 199 | expect(stdout).not.to.match(/2 passing/); 200 | expect(stdout).to.match(/Done./); 201 | expect(stderr).to.equal(''); 202 | done(); 203 | }); 204 | }); 205 | 206 | it('should support the grep option', function(done) { 207 | execScenario('grepOption', function(error, stdout, stderr) { 208 | expect(stdout).to.match(/tests that match grep/); 209 | expect(stdout).to.match(/1 passing/); 210 | expect(stdout).to.match(/Done./); 211 | expect(stderr).to.equal(''); 212 | done(); 213 | }); 214 | }); 215 | 216 | it('should support the invert option', function(done) { 217 | execScenario('invertOption', function(error, stdout, stderr) { 218 | expect(stdout).to.match(/tests that don't match grep/); 219 | expect(stdout).to.match(/1 passing/); 220 | expect(stdout).to.match(/Done./); 221 | expect(stderr).to.equal(''); 222 | done(); 223 | }); 224 | }); 225 | 226 | it('should support the ignoreLeaks option', function(done) { 227 | execScenario('ignoreLeaksOption', function(error, stdout, stderr) { 228 | expect(stdout).to.match(/test/); 229 | expect(stdout).to.match(/Aborted due to warnings./); 230 | expect(stdout).to.match(/1 failing/); 231 | expect(stdout).to.match(/Error: global leak detected: leak/); 232 | expect(stderr).to.equal(''); 233 | done(); 234 | }); 235 | }); 236 | 237 | it('should support the globals option', function(done) { 238 | execScenario('globalsOption', function(error, stdout, stderr) { 239 | expect(stdout).to.match(/test/); 240 | expect(stdout).to.match(/1 passing/); 241 | expect(stdout).to.match(/Done./); 242 | expect(stderr).to.equal(''); 243 | done(); 244 | }); 245 | }); 246 | 247 | it('should support the asyncOnly option', function(done) { 248 | execScenario('asyncOnlyOption', function(error, stdout, stderr) { 249 | expect(stdout).to.match(/test/); 250 | expect(stdout).to.match(/Aborted due to warnings./); 251 | expect(stdout).to.match(/1 failing/); 252 | expect(stdout).to.match(/Error: --async-only option in use without declaring/); 253 | expect(stderr).to.equal(''); 254 | done(); 255 | }); 256 | }); 257 | 258 | it('should support the reporter option', function(done) { 259 | execScenario('reporterOption', function(error, stdout, stderr) { 260 | expect(stdout).to.match(/
/); 261 | expect(stderr).to.equal(''); 262 | done(); 263 | }); 264 | }); 265 | 266 | it('should support the reporter option via CLI', function(done) { 267 | execScenario('reporterOption', function(error, stdout, stderr) { 268 | expect(stdout).to.match(/Running "mochaTest:all"/); 269 | expect(stderr).to.equal(''); 270 | done(); 271 | }, '--reporter=spec'); 272 | }); 273 | 274 | it('should support the ui option', function(done) { 275 | execScenario('uiOption', function(error, stdout, stderr) { 276 | expect(stdout).to.match(/test1/); 277 | expect(stdout).to.match(/test2/); 278 | expect(stdout).to.match(/2 passing/); 279 | expect(stdout).to.match(/Done./); 280 | expect(stderr).to.equal(''); 281 | done(); 282 | }); 283 | }); 284 | 285 | it('should support using a custom ui option', function(done) { 286 | execScenario('uiOptionCustom', function(error, stdout, stderr) { 287 | expect(stdout).to.match(/test/); 288 | expect(stdout).to.match(/1 passing/); 289 | expect(stdout).to.match(/Done./); 290 | expect(stderr).to.equal(''); 291 | done(); 292 | }); 293 | }); 294 | 295 | it('should support the timeout option', function(done) { 296 | execScenario('timeoutOption', function(error, stdout, stderr) { 297 | expect(stdout).to.match(/test/); 298 | expect(stdout).to.match(/Aborted due to warnings./); 299 | expect(stdout).to.match(/1 failing/); 300 | expect(stdout).to.match(/Error: Timeout of 500ms exceeded/); 301 | expect(stderr).to.equal(''); 302 | done(); 303 | }); 304 | }); 305 | 306 | it('should support the growl option', function(done) { 307 | execScenario('growlOption', function(error, stdout, stderr) { 308 | // TODO: Let's just test that everything completed successfully 309 | // as there's no way of knowing if growl was actually called for now. 310 | // A possible option would be to mock the growl binaries in the 311 | // growlOption scenario directory and have them do something that 312 | // the test can detect (HTTP server/request?). This would have to 313 | // be done for each platform though. 314 | expect(stdout).to.match(/test1/); 315 | expect(stdout).to.match(/test2/); 316 | expect(stdout).to.match(/2 passing/); 317 | expect(stdout).to.match(/Done./); 318 | expect(stderr).to.equal(''); 319 | done(); 320 | }); 321 | }); 322 | 323 | it('should support a destination file to write output', function(done) { 324 | var destinationFile = __dirname + '/../scenarios/destinationFile/output'; 325 | 326 | // first remove the destination file 327 | if (fs.existsSync(destinationFile)) { 328 | fs.unlinkSync(destinationFile); 329 | } 330 | 331 | execScenario('destinationFile', function(error, stdout, stderr) { 332 | expect(stdout).to.match(/test1/); 333 | expect(stdout).to.match(/test2/); 334 | expect(stdout).to.match(/2 passing/); 335 | expect(stdout).to.match(/Done./); 336 | expect(stderr).to.equal(''); 337 | 338 | // now read the destination file 339 | var output = fs.readFileSync(destinationFile, 'utf8'); 340 | expect(output).to.match(/test1/); 341 | expect(output).to.match(/test2/); 342 | expect(output).to.match(/2 passing/); 343 | 344 | done(); 345 | }); 346 | }); 347 | 348 | it('should create parent directories for destination file', function(done) { 349 | var destinationDirectory = path.join(__dirname, '/../scenarios/destinationFileCreateDirectories/reports'); 350 | var destinationFile = path.join(destinationDirectory, 'output'); 351 | 352 | rimrafSync(destinationDirectory); 353 | 354 | execScenario('destinationFileCreateDirectories', function(error, stdout, stderr) { 355 | expect(stdout).to.match(/test1/); 356 | expect(stdout).to.match(/test2/); 357 | expect(stdout).to.match(/2 passing/); 358 | expect(stdout).to.match(/Done./); 359 | expect(stderr).to.equal(''); 360 | 361 | // now read the destination file 362 | var output = fs.readFileSync(destinationFile, 'utf8'); 363 | expect(output).to.match(/test1/); 364 | expect(output).to.match(/test2/); 365 | expect(output).to.match(/2 passing/); 366 | 367 | done(); 368 | }); 369 | }); 370 | 371 | it('should support the quiet option', function(done) { 372 | var destinationFile = __dirname + '/../scenarios/quietOption/output'; 373 | 374 | // first remove the destination file 375 | if (fs.existsSync(destinationFile)) { 376 | fs.unlinkSync(destinationFile); 377 | } 378 | 379 | execScenario('quietOption', function(error, stdout, stderr) { 380 | expect(stdout).to.not.match(/test1/); 381 | expect(stdout).to.not.match(/test2/); 382 | expect(stdout).to.not.match(/2 passing/); 383 | expect(stdout).to.match(/Done./); 384 | expect(stderr).to.equal(''); 385 | 386 | // now read the destination file 387 | var output = fs.readFileSync(destinationFile, 'utf8'); 388 | expect(output).to.match(/test1/); 389 | expect(output).to.match(/test2/); 390 | expect(output).to.match(/2 passing/); 391 | 392 | done(); 393 | }); 394 | }); 395 | 396 | it('should not run if the src config do not match any files', function(done) { 397 | execScenario('noFiles', function(error, stdout, stderr) { 398 | expect(stdout).to.match(/No files to check.../); 399 | expect(stdout).to.match(/Done./); 400 | expect(stdout).not.to.match(/0 passing/); 401 | expect(stderr).to.equal(''); 402 | done(); 403 | }); 404 | }); 405 | 406 | it('should work with grunt-env', function(done) { 407 | execScenario('gruntEnvIntegration', function(error, stdout, stderr) { 408 | expect(stdout).to.match(/test/); 409 | expect(stdout).to.match(/1 passing/); 410 | expect(stdout).to.match(/Done./); 411 | expect(stderr).to.equal(''); 412 | done(); 413 | }); 414 | }); 415 | 416 | it('should work with the xunit reporter', function(done) { 417 | execScenario('xunitReporter', function(error, stdout, stderr) { 418 | expect(stdout).to.match(/test/); 419 | expect(stdout).to.match(/tests="1"/); 420 | expect(stdout).to.match(/failures="0"/); 421 | expect(stdout).to.match(/errors="0"/); 422 | expect(stdout).to.match(/skipped="0"/); 423 | expect(stdout).to.match(/Done./); 424 | expect(stderr).to.equal(''); 425 | done(); 426 | }); 427 | }); 428 | 429 | it('should support reporterOptions', function(done) { 430 | var destinationFile = __dirname + '/../scenarios/reporterOptions/output'; 431 | 432 | // first remove the destination file 433 | if (fs.existsSync(destinationFile)) { 434 | fs.unlinkSync(destinationFile); 435 | } 436 | 437 | execScenario('reporterOptions', function(error, stdout, stderr) { 438 | expect(stdout).to.not.match(/test/); 439 | expect(stdout).to.not.match(/tests="1000"/); 440 | expect(stdout).to.not.match(/failures="0"/); 441 | expect(stdout).to.not.match(/errors="0"/); 442 | expect(stdout).to.not.match(/skipped="0"/); 443 | expect(stdout).to.match(/Done./); 444 | expect(stderr).to.equal(''); 445 | 446 | // now read the destination file 447 | var output = fs.readFileSync(destinationFile, 'utf8'); 448 | expect(output).to.match(/test/); 449 | expect(output).to.match(/tests="1000"/); 450 | expect(output).to.match(/failures="0"/); 451 | expect(output).to.match(/errors="0"/); 452 | expect(output).to.match(/skipped="0"/); 453 | expect(output).to.match(//); 454 | expect(output).to.match(/<\/testsuite>/); 455 | 456 | done(); 457 | }); 458 | }); 459 | }); 460 | --------------------------------------------------------------------------------