title: My karma unit test executed but not stopping itself (using grunt)
body: <p>I am running Karma to execute unit test cases using Grunt. It is running perfectly well, but the Karma process is not getting stopped automatically after test execution completion. No error/no log. Following are details on config and grunt file.</p>
  
  <p><strong>karma-config.js</strong></p>
  
  <pre><code>module.exports = function(config) {
      config.set({
          // base path, that will be used to resolve files and exclude
          basePath: './../../../../',
          // frameworks to use
          frameworks: ['jasmine'],
          // generate js files from html templates
          preprocessors: {
              'ThemeLibrary/client/templates/categoryview/Category.html': 'ng-html2js'
          },
          // list of files / patterns to load in the browser
          files: [
              //Note: Order of file listing does matter therefore loading using * may cause issue
              //Load external libraries 
              'ThemeLibrary/client/js/vendor/others/underscore-min_1.6.0.js',
              'ThemeLibrary/client/js/vendor/jquery/jquery.min-1.9.1.js',
              'ThemeLibrary/client/js/vendor/angularjs/angular.min.js',
              'ThemeLibrary/client/js/vendor/angularjs/angular-resource.min.js',
              'ThemeLibrary/client/js/vendor/angularjs/angular-route.min.js',
              'ThemeLibrary/client/js/vendor/angularjs/keypress.js',
              'ThemeLibrary/client/js/vendor/angularjs/truncate.js',
              'Test/unit/client/lib/angularjs/angular-mocks.js',
              'Test/unit/client/lib/jasmin/JasminHelper.js',
              //Load application library used by code.
              'ThemeLibrary/client/js/application/utilities/JavascriptExtension.js',
              'ThemeLibrary/client/js/application/App.js',
              //Load directives HTML templates
              'ThemeLibrary/client/templates/categoryview/Category.html',
              //Load application source code which needs to be tested
              'ThemeLibrary/client/js/application/utilities/*.js',
              'ThemeLibrary/client/js/application/controllers/*.js',
              'ThemeLibrary/client/js/application/services/*.js',
              'ThemeLibrary/client/js/application/factories/*.js',
              'ThemeLibrary/client/js/application/factories/implementation/*.js',
              'ThemeLibrary/client/js/application/directives/categoryview/Category.js',
              //Load test data            
              'Test/unit/client/testdata/*.js',
              'Test/unit/client/js/mock/*.js',
              //Test files
              'Test/unit/client/js/application/utilities/*.js',
              'Test/unit/client/js/application/controllers/*.js',
              'Test/unit/client/js/application/services/*.js',
              'Test/unit/client/js/application/factories/implementation/*.js',
              'Test/unit/client/js/application/factories/*.js',
              //'Test/unit/client/js/application/directives/categoryview/Category.test.js'
          ],
          // list of files to exclude
          exclude: [
          ],
          // test results reporter to use
          reporters: ['progress'],
          // web server port
          port: 9101,
          // enable / disable colors in the output (reporters and logs)
          colors: true,
          // level of logging
          logLevel: config.LOG_INFO,
          // enable / disable watching file and executing tests whenever any file changes
          autoWatch: true,
          // Start these browsers
          browsers: ['PhantomJS'],
          // If browser does not capture in given timeout [ms], kill it
          captureTimeout: 60000,
          // Continuous Integration mode
          // if true, it capture browsers, run tests and exit
          singleRun: false,
          ngHtml2JsPreprocessor: {
              'moduleName': 'Templates',
              stripPrefix: '.*/ThemeLibrary/client',
              // Function that transforms the path to look exactly like you have it in templateUrl in your Angular code    
              cacheIdFromPath: function(filepath) {
  
                  //return filepath.match(/\/templates\/categoryview\/.*\.html/);
                  //return filepath.match('/templates/categoryview/Category.html');
                  //return 'ThemeLibrary/client'+filepath;
                  return filepath;
                   //return 'ThemeLibrary/client/templates/categoryview/Category.html';
  
              }
          }
      });
  };
  </code></pre>
  
  <p><strong>Gruntfile.js</strong></p>
  
  <pre><code>/**
   * New node file
   */
  module.exports = function(grunt){
  
      //globalConfig and paths which will used in the grunt script
  
      var config={
  
              srcFolderName: 'src',
              distFolderName: 'dist',
              appFileName: 'server.js',
              nodeModuleFolderName: 'node_modules',
                          testSourceFolderName: 'src-test',
                          testDestFolderName: 'Test',
              //change this command based on project requirement
              apiDocCommand:'apidoc -i src/server -o apidoc',
              npmInstallCommand: 'npm install --prefix ./dist/&lt;%= pkg.name %&gt;/node_modules'
  
      }
  
      //init
      grunt.initConfig({
          config:config,
          pkg: grunt.file.readJSON('package.json'),
          copy: {
  
              //copy all source files to distribution folder
              sourceFiles: {
                cwd: '&lt;%= config.srcFolderName %&gt;',
                src: [ '**' ],
                dest: '&lt;%= config.distFolderName %&gt;/&lt;%= pkg.name %&gt;',
                expand: true
              },
              //copy main app file to dist folder
              mainAppFile: {
                  src: '&lt;%= config.appFileName %&gt;',
                  dest: '&lt;%= config.distFolderName %&gt;/&lt;%= pkg.name %&gt;/&lt;%= config.appFileName %&gt;'
              },
              copyPackage:{
                  src: 'package.json',
                  dest: '&lt;%= config.distFolderName %&gt;/&lt;%= pkg.name %&gt;/package.json'
              },
              //copy all source test files to distribution folder
              testFiles: {
                cwd: '&lt;%= config.testSourceFolderName %&gt;',
                src: [ '**' ],
                dest: '&lt;%= config.distFolderName %&gt;/&lt;%= config.testDestFolderName %&gt;',
                expand: true
              }
            },
            clean : {
                build : {
                    src : [ '&lt;%=config.distFolderName%&gt;/','apidoc/' ]
                },
                pkgJson : {
                    src : ['&lt;%= config.distFolderName %&gt;/&lt;%= pkg.name %&gt;/package.json']
                }
            },
            uglify: {
                serverCode:{
                    files: [{
                        expand:true,
                        cwd:'&lt;%= config.distFolderName %&gt;/&lt;%= pkg.name %&gt;/server',
                        src:'**/*.js',
                        dest:'&lt;%= config.distFolderName %&gt;/&lt;%= pkg.name %&gt;/server'
                    }]
                },
                clientCode:{
                    files: [{
                        expand:true,
                        cwd:'&lt;%= config.distFolderName %&gt;/&lt;%= pkg.name %&gt;/client/js/application',
                        src:'**/*.js',
                        dest:'&lt;%= config.distFolderName %&gt;/&lt;%= pkg.name %&gt;/client/js/application'
                    }]
                },
                mainAppFile: {
                    files: {
                         '&lt;%= config.distFolderName %&gt;/&lt;%= pkg.name %&gt;/&lt;%= config.appFileName %&gt;':['&lt;%= config.distFolderName %&gt;/&lt;%= pkg.name %&gt;/&lt;%= config.appFileName %&gt;']
                    }
                }
            },
            jshint:{
                serverCode:{
                    files:[{
                        expand:true,
                        cwd:'&lt;%= config.distFolderName %&gt;/&lt;%= pkg.name %&gt;/server',
                        src:'**/*.js'
                    }]
                },
                clientCode:{
                    files: [{
                        expand:true,
                        cwd:'&lt;%= config.distFolderName %&gt;/&lt;%= pkg.name %&gt;/client/js/application',
                        src:'**/*.js'
                    }]
                },
                    clientTestCode:{
                    files: [{
                        expand:true,
                        cwd:'&lt;%= config.distFolderName %&gt;/&lt;%= config.testDestFolderName %&gt;/unit/client/js',
                        src:'**/*.js'
                    }]
                },
                    serverTestCode:{
                    files: [{
                        expand:true,
                        cwd:'&lt;%= config.distFolderName %&gt;/&lt;%= config.testDestFolderName %&gt;/server',
                        src:'**/*.js'
                    }]
                }
            },
            //mocha is used to automate unit testing of server side nodejs/express code.
            simplemocha: {
              options: {
                  globals: ['expect'],
                  timeout: 3000,
                  ignoreLeaks: false,
                  ui: 'bdd',
                  reporter: 'tap'
              },
              all: { src: ['dist/Test/unit/server/**/*.js'] }
          },
          //karma is used to automate unit testing of client side angular/javascript test cases writtin in jasmine.
          karma: {
              unit: {
                  configFile: 'dist/Test/unit/client/config/karma.conf.js',
                  background: false
              }
          },
          protractor: {
                      options: {
                            configFile: "protractor-config.js", //your protractor config file
                            keepAlive: true, // If false, the grunt process stops when the test fails.
                            noColor: false, // If true, protractor will not use colors in its output.
                            args: {
                                // Arguments passed to the command
                            }
                        },
                      chrome: {
                          options: {
                                args: {
                                      browser: "chrome"
                                }
                            }
                      },
                      safari: {
                          options: {
                              args: {
                                  browser: "safari"
                              }
                          }
                      },
                      firefox: {
                          options: {
                              args: {
                                  browser: "firefox"
                              }
                          }
                      }
                  },
           exec: {
                    generateAPIDoc : {
                        command: '&lt;%= config.apiDocCommand %&gt;'
                    },
                    buildDependencies :{
                        command: '&lt;%= config.npmInstallCommand %&gt;'
                    }
            }
      });
  
      // load our tasks
      grunt.loadNpmTasks('grunt-contrib-copy');
      grunt.loadNpmTasks('grunt-contrib-clean');
      grunt.loadNpmTasks('grunt-contrib-uglify');
      grunt.loadNpmTasks('grunt-contrib-jshint');
      grunt.loadNpmTasks('grunt-simple-mocha');
      grunt.loadNpmTasks('grunt-karma');
      grunt.loadNpmTasks('grunt-protractor-runner');
      //for running executables
      grunt.loadNpmTasks('grunt-exec');
  
      grunt.registerTask('start-server', 'Start a custom web server', function() {
          grunt.log.writeln('Started web server on port 3000');
          require('./dist/ThemeLibrary/server.js');
      });
  
      //register the tasks
      grunt.registerTask('build',
              'Compiles all of the assets and copies the files to the build directory for Dev', 
              [ 'clean:build', 'clean:pkgJson','copy','exec:buildDependencies','jshint','exec:generateAPIDoc','uglify:serverCode','uglify:clientCode','uglify:mainAppFile','simplemocha','start-server', 'karma:unit']
      );
      grunt.registerTask('build-dev',
              'Only copies the source files for Dev', 
              [ 'copy:sourceFiles','copy:mainAppFile', 'copy:testFiles', 'jshint', 'simplemocha','start-server','karma:unit']
      );
  };
  </code></pre>
  
  <p><strong>package.json</strong></p>
  
  <pre><code>{
      "name": "ThemeLibrary",
      "version": "0.0.1",
      "private": true,
      "scripts": {
          "install": "node ./node_modules/protractor/bin/webdriver-manager update --standalone",
          "start": "node ./dist/ThemeLibrary/server.js",
          "start": "node ./node_modules/protractor/bin/webdriver-manager start",
          "start": "node ./node_modules/protractor/bin/protractor ./dist/Test/integration/config/protractor-config.js"
  
      },
      "repository": {
      "type": "git",
      "url": "https://devops-tools.pearson.com/stash/projects/PTL/repos/pxe_theme_library/browse/ThemeLibrary"
    },
      "dependencies": {
          "express": "*",
          "body-parser": "*",
          "connect-busboy": "*",
          "cookie-parser": "*",
          "express-session": "*",
          "morgan": "*",
          "ejs": "*",
          "bcrypt-nodejs": "*",
          "mongodb": "*",
          "mongoskin": "*",
          "connect-flash": "*",
          "string": "*"
      },
      "devDependencies": {
          "grunt": "*",
          "chai": "*",
          "mocha": "*",
          "karma": "*",
          "grunt-contrib-copy": "*",
          "grunt-contrib-clean": "*",
          "grunt-contrib-uglify": "*",
          "grunt-contrib-jshint": "*",
          "grunt-simple-mocha": "*",
          "grunt-exec": "*",
          "karma-script-launcher": "*",
          "karma-chrome-launcher": "*",
          "karma-firefox-launcher": "*",
          "karma-ie-launcher": "*",
          "karma-jasmine": "*",
          "karma-phantomjs-launcher": "*",
          "karma-story-reporter": "*",
          "grunt-karma": "*",
          "grunt-cli": "*",
          "karma-sauce-launcher": "*",
          "phantomjs": "*",
          "karma-ng-html2js-preprocessor": "*",
          "node-inspector": "*",
          "protractor": "0.22.0",
          "grunt-protractor-runner": "*"
      }
  }
  </code></pre>