title: Warning: Task "karma" not found when running grunt test
body: <p><a href="http://www.sitepoint.com/kickstart-your-angularjs-development-with-yeoman-grunt-and-bower">http://www.sitepoint.com/kickstart-your-angularjs-development-with-yeoman-grunt-and-bower</a></p>
  
  <p>After following this interesting guide about Angular, Yeoman, Bower and Grunt I was able tot bootstrap an Angular application.</p>
  
  <p>Everything works fine except the testing with Karma. When I run:</p>
  
  <pre><code>grunt test
  </code></pre>
  
  <p>I get the following error:</p>
  
  <pre><code>Warning: Task "karma" not found. Used --force, continuing.
  
  Done, but with warnings
  </code></pre>
  
  <p>I checked if I have installed Karma, but that is installed. For Grunt it appears you need to install grunt-karma. So I tried that throughout the following command:</p>
  
  <pre><code>npm install grunt-karma --save-dev
  </code></pre>
  
  <p>This gives me errrors like:</p>
  
  <pre><code>errno: 53,
  code: 'ENOTEMPTY',
  path: 'C:\\tmp\\phantomjs\\phantom-1.9.2-windows-.zip-extract-' ..
  </code></pre>
  
  <p>I am on Windows and executing commands from the powershell.</p>
  
  <p>Hope someone can help.</p>
  
  <p>Edit karma.conf.js and gruntfile</p>
  
  <pre><code>// Karma configuration
  // http://karma-runner.github.io/0.10/config/configuration-file.html
  
  module.exports = function(config) {
    config.set({
      // base path, that will be used to resolve files and exclude
      basePath: '',
  
      // testing framework to use (jasmine/mocha/qunit/...)
      frameworks: ['jasmine'],
  
      // list of files / patterns to load in the browser
      files: [
        'app/bower_components/angular/angular.js',
        'app/bower_components/angular-mocks/angular-mocks.js',
        'app/bower_components/angular-resource/angular-resource.js',
        'app/bower_components/angular-cookies/angular-cookies.js',
        'app/bower_components/angular-sanitize/angular-sanitize.js',
        'app/scripts/*.js',
        'app/scripts/**/*.js',
        'test/mock/**/*.js',
        'test/spec/**/*.js'
      ],
  
      // list of files / patterns to exclude
      exclude: [],
  
      // web server port
      port: 8080,
  
      // level of logging
      // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
      logLevel: config.LOG_INFO,
  
  
      // enable / disable watching file and executing tests whenever any file changes
      autoWatch: false,
  
  
      // Start these browsers, currently available:
      // - Chrome
      // - ChromeCanary
      // - Firefox
      // - Opera
      // - Safari (only Mac)
      // - PhantomJS
      // - IE (only Windows)
      browsers: ['Chrome'],
  
  
      // Continuous Integration mode
      // if true, it capture browsers, run tests and exit
      singleRun: false
    });
  };
  </code></pre>
  
  <p>Gruntfile</p>
  
  <pre><code>    // Generated on 2013-11-02 using generator-angular 0.5.1
  'use strict';
  
  // # Globbing
  // for performance reasons we're only matching one level down:
  // 'test/spec/{,*/}*.js'
  // use this if you want to recursively match all subfolders:
  // 'test/spec/**/*.js'
  
  module.exports = function (grunt) {
    grunt.loadNpmTasks('grunt-karma');
    require('load-grunt-tasks')(grunt);
    require('time-grunt')(grunt);
  
    grunt.initConfig({
      yeoman: {
        // configurable paths
        app: require('./bower.json').appPath || 'app',
        dist: 'dist'
      },
      watch: {
        coffee: {
          files: ['&lt;%= yeoman.app %&gt;/scripts/{,*/}*.coffee'],
          tasks: ['coffee:dist']
        },
        coffeeTest: {
          files: ['test/spec/{,*/}*.coffee'],
          tasks: ['coffee:test']
        },
        compass: {
          files: ['&lt;%= yeoman.app %&gt;/styles/{,*/}*.{scss,sass}'],
          tasks: ['compass:server', 'autoprefixer']
        },
        styles: {
          files: ['&lt;%= yeoman.app %&gt;/styles/{,*/}*.css'],
          tasks: ['copy:styles', 'autoprefixer']
        },
        livereload: {
          options: {
            livereload: '&lt;%= connect.options.livereload %&gt;'
          },
          files: [
            '&lt;%= yeoman.app %&gt;/{,*/}*.html',
            '.tmp/styles/{,*/}*.css',
            '{.tmp,&lt;%= yeoman.app %&gt;}/scripts/{,*/}*.js',
            '&lt;%= yeoman.app %&gt;/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
          ]
        }
      },
      autoprefixer: {
        options: ['last 1 version'],
        dist: {
          files: [{
            expand: true,
            cwd: '.tmp/styles/',
            src: '{,*/}*.css',
            dest: '.tmp/styles/'
          }]
        }
      },
      connect: {
        options: {
          port: 9000,
          // Change this to '0.0.0.0' to access the server from outside.
          hostname: 'localhost',
          livereload: 35729
        },
        livereload: {
          options: {
            open: true,
            base: [
              '.tmp',
              '&lt;%= yeoman.app %&gt;'
            ]
          }
        },
        test: {
          options: {
            port: 9001,
            base: [
              '.tmp',
              'test',
              '&lt;%= yeoman.app %&gt;'
            ]
          }
        },
        dist: {
          options: {
            base: '&lt;%= yeoman.dist %&gt;'
          }
        }
      },
      clean: {
        dist: {
          files: [{
            dot: true,
            src: [
              '.tmp',
              '&lt;%= yeoman.dist %&gt;/*',
              '!&lt;%= yeoman.dist %&gt;/.git*'
            ]
          }]
        },
        server: '.tmp'
      },
      jshint: {
        options: {
          jshintrc: '.jshintrc'
        },
        all: [
          'Gruntfile.js',
          '&lt;%= yeoman.app %&gt;/scripts/{,*/}*.js'
        ]
      },
      coffee: {
        options: {
          sourceMap: true,
          sourceRoot: ''
        },
        dist: {
          files: [{
            expand: true,
            cwd: '&lt;%= yeoman.app %&gt;/scripts',
            src: '{,*/}*.coffee',
            dest: '.tmp/scripts',
            ext: '.js'
          }]
        },
        test: {
          files: [{
            expand: true,
            cwd: 'test/spec',
            src: '{,*/}*.coffee',
            dest: '.tmp/spec',
            ext: '.js'
          }]
        }
      },
      compass: {
        options: {
          sassDir: '&lt;%= yeoman.app %&gt;/styles',
          cssDir: '.tmp/styles',
          generatedImagesDir: '.tmp/images/generated',
          imagesDir: '&lt;%= yeoman.app %&gt;/images',
          javascriptsDir: '&lt;%= yeoman.app %&gt;/scripts',
          fontsDir: '&lt;%= yeoman.app %&gt;/styles/fonts',
          importPath: '&lt;%= yeoman.app %&gt;/bower_components',
          httpImagesPath: '/images',
          httpGeneratedImagesPath: '/images/generated',
          httpFontsPath: '/styles/fonts',
          relativeAssets: false
        },
        dist: {},
        server: {
          options: {
            debugInfo: true
          }
        }
      },
      // not used since Uglify task does concat,
      // but still available if needed
      /*concat: {
        dist: {}
      },*/
      rev: {
        dist: {
          files: {
            src: [
              '&lt;%= yeoman.dist %&gt;/scripts/{,*/}*.js',
              '&lt;%= yeoman.dist %&gt;/styles/{,*/}*.css',
              '&lt;%= yeoman.dist %&gt;/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
              '&lt;%= yeoman.dist %&gt;/styles/fonts/*'
            ]
          }
        }
      },
      useminPrepare: {
        html: '&lt;%= yeoman.app %&gt;/index.html',
        options: {
          dest: '&lt;%= yeoman.dist %&gt;'
        }
      },
      usemin: {
        html: ['&lt;%= yeoman.dist %&gt;/{,*/}*.html'],
        css: ['&lt;%= yeoman.dist %&gt;/styles/{,*/}*.css'],
        options: {
          dirs: ['&lt;%= yeoman.dist %&gt;']
        }
      },
      imagemin: {
        dist: {
          files: [{
            expand: true,
            cwd: '&lt;%= yeoman.app %&gt;/images',
            src: '{,*/}*.{png,jpg,jpeg}',
            dest: '&lt;%= yeoman.dist %&gt;/images'
          }]
        }
      },
      svgmin: {
        dist: {
          files: [{
            expand: true,
            cwd: '&lt;%= yeoman.app %&gt;/images',
            src: '{,*/}*.svg',
            dest: '&lt;%= yeoman.dist %&gt;/images'
          }]
        }
      },
      cssmin: {
        // By default, your `index.html` &lt;!-- Usemin Block --&gt; will take care of
        // minification. This option is pre-configured if you do not wish to use
        // Usemin blocks.
        // dist: {
        //   files: {
        //     '&lt;%= yeoman.dist %&gt;/styles/main.css': [
        //       '.tmp/styles/{,*/}*.css',
        //       '&lt;%= yeoman.app %&gt;/styles/{,*/}*.css'
        //     ]
        //   }
        // }
      },
      htmlmin: {
        dist: {
          options: {
            /*removeCommentsFromCDATA: true,
            // https://github.com/yeoman/grunt-usemin/issues/44
            //collapseWhitespace: true,
            collapseBooleanAttributes: true,
            removeAttributeQuotes: true,
            removeRedundantAttributes: true,
            useShortDoctype: true,
            removeEmptyAttributes: true,
            removeOptionalTags: true*/
          },
          files: [{
            expand: true,
            cwd: '&lt;%= yeoman.app %&gt;',
            src: ['*.html', 'views/*.html'],
            dest: '&lt;%= yeoman.dist %&gt;'
          }]
        }
      },
      // Put files not handled in other tasks here
      copy: {
        dist: {
          files: [{
            expand: true,
            dot: true,
            cwd: '&lt;%= yeoman.app %&gt;',
            dest: '&lt;%= yeoman.dist %&gt;',
            src: [
              '*.{ico,png,txt}',
              '.htaccess',
              'bower_components/**/*',
              'images/{,*/}*.{gif,webp}',
              'styles/fonts/*'
            ]
          }, {
            expand: true,
            cwd: '.tmp/images',
            dest: '&lt;%= yeoman.dist %&gt;/images',
            src: [
              'generated/*'
            ]
          }]
        },
        styles: {
          expand: true,
          cwd: '&lt;%= yeoman.app %&gt;/styles',
          dest: '.tmp/styles/',
          src: '{,*/}*.css'
        }
      },
      concurrent: {
        server: [
          'coffee:dist',
          'compass:server',
          'copy:styles'
        ],
        test: [
          'coffee',
          'compass',
          'copy:styles'
        ],
        dist: [
          'coffee',
          'compass:dist',
          'copy:styles',
          'imagemin',
          'svgmin',
          'htmlmin'
        ]
      },
      karma: {
        unit: {
          configFile: 'karma.conf.js',
          singleRun: true
        }
      },
      cdnify: {
        dist: {
          html: ['&lt;%= yeoman.dist %&gt;/*.html']
        }
      },
      ngmin: {
        dist: {
          files: [{
            expand: true,
            cwd: '&lt;%= yeoman.dist %&gt;/scripts',
            src: '*.js',
            dest: '&lt;%= yeoman.dist %&gt;/scripts'
          }]
        }
      },
      uglify: {
        dist: {
          files: {
            '&lt;%= yeoman.dist %&gt;/scripts/scripts.js': [
              '&lt;%= yeoman.dist %&gt;/scripts/scripts.js'
            ]
          }
        }
      }
    });
  
    grunt.registerTask('server', function (target) {
      if (target === 'dist') {
        return grunt.task.run(['build', 'connect:dist:keepalive']);
      }
  
      grunt.task.run([
        'clean:server',
        'concurrent:server',
        'autoprefixer',
        'connect:livereload',
        'watch'
      ]);
    });
  
    grunt.registerTask('test', [
      'clean:server',
      'concurrent:test',
      'autoprefixer',
      'connect:test',
      'karma'
    ]);
  
    grunt.registerTask('build', [
      'clean:dist',
      'useminPrepare',
      'concurrent:dist',
      'autoprefixer',
      'concat',
      'copy:dist',
      'cdnify',
      'ngmin',
      'cssmin',
      'uglify',
      'rev',
      'usemin'
    ]);
  
    grunt.registerTask('default', [
      'jshint',
      'test',
      'build'
    ]);
  };
  </code></pre>