title: generator-angular: task "karma" not found when calling `grunt test`
body: <p>I'm trying to setup a development environment with Yeoman for AngularJS,
  I installed Yeoman according to the instructions: <code>sudo npm install -g yo bower grunt-cli generator-angular</code> and I'm generating a new app with <code>yo angular</code>.</p>
  
  <p>After the app is generated, running <code>karma start</code> does start the karma server, but running <code>grunt test</code> result in</p>
  
  <pre><code>Loading "grunt-karma.js" tasks...ERROR
  &gt;&gt; TypeError: object is not a function
  Warning: Task "karma" not found. Use --force to continue.
  
  Aborted due to warnings.
  </code></pre>
  
  <p>how do I fix this ?</p>
  
  <p>EDIT: some files (generated fresh from Yeoman)</p>
  
  <p>Gruntfile.js:</p>
  
  <pre><code>'use strict';
  var lrSnippet = require('grunt-contrib-livereload/lib/utils').livereloadSnippet;
  var mountFolder = function (connect, dir) {
    return connect.static(require('path').resolve(dir));
  };
  
  module.exports = function (grunt) {
    // load all grunt tasks
    require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
  
    // configurable paths
    var yeomanConfig = {
      app: 'app',
      dist: 'dist'
    };
  
    try {
      yeomanConfig.app = require('./component.json').appPath || yeomanConfig.app;
    } catch (e) {}
  
    grunt.initConfig({
      yeoman: yeomanConfig,
      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']
        },
        livereload: {
          files: [
            '&lt;%= yeoman.app %&gt;/{,*/}*.html',
            '{.tmp,&lt;%= yeoman.app %&gt;}/styles/{,*/}*.css',
            '{.tmp,&lt;%= yeoman.app %&gt;}/scripts/{,*/}*.js',
            '&lt;%= yeoman.app %&gt;/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
          ],
          tasks: ['livereload']
        }
      },
      connect: {
        options: {
          port: 9000,
          // Change this to '0.0.0.0' to access the server from outside.
          hostname: 'localhost'
        },
        livereload: {
          options: {
            middleware: function (connect) {
              return [
                lrSnippet,
                mountFolder(connect, '.tmp'),
                mountFolder(connect, yeomanConfig.app)
              ];
            }
          }
        },
        test: {
          options: {
            middleware: function (connect) {
              return [
                mountFolder(connect, '.tmp'),
                mountFolder(connect, 'test')
              ];
            }
          }
        }
      },
      open: {
        server: {
          url: 'http://localhost:&lt;%= connect.options.port %&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'
        ]
      },
      karma: {
        unit: {
          configFile: 'karma.conf.js',
          singleRun: true
        }
      },
      coffee: {
        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',
          imagesDir: '&lt;%= yeoman.app %&gt;/images',
          javascriptsDir: '&lt;%= yeoman.app %&gt;/scripts',
          fontsDir: '&lt;%= yeoman.app %&gt;/styles/fonts',
          importPath: '&lt;%= yeoman.app %&gt;/components',
          relativeAssets: true
        },
        dist: {},
        server: {
          options: {
            debugInfo: true
          }
        }
      },
      concat: {
        dist: {
          files: {
            '&lt;%= yeoman.dist %&gt;/scripts/scripts.js': [
              '.tmp/scripts/{,*/}*.js',
              '&lt;%= yeoman.app %&gt;/scripts/{,*/}*.js'
            ]
          }
        }
      },
      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'
          }]
        }
      },
      cssmin: {
        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;'
          }]
        }
      },
      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'
            ]
          }
        }
      },
      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/*'
            ]
          }
        }
      },
      copy: {
        dist: {
          files: [{
            expand: true,
            dot: true,
            cwd: '&lt;%= yeoman.app %&gt;',
            dest: '&lt;%= yeoman.dist %&gt;',
            src: [
              '*.{ico,txt}',
              '.htaccess',
              'components/**/*',
              'images/{,*/}*.{gif,webp}',
              'styles/fonts/*'
            ]
          }]
        }
      }
    });
  
    grunt.renameTask('regarde', 'watch');
  
    grunt.registerTask('server', [
      'clean:server',
      'coffee:dist',
      'compass:server',
      'livereload-start',
      'connect:livereload',
      'open',
      'watch'
    ]);
  
    grunt.registerTask('test', [
      'clean:server',
      'coffee',
      'compass',
      'connect:test',
      'karma'
    ]);
  
    grunt.registerTask('build', [
      'clean:dist',
      'jshint',
      'test',
      'coffee',
      'compass:dist',
      'useminPrepare',
      'imagemin',
      'cssmin',
      'htmlmin',
      'concat',
      'copy',
      'cdnify',
      'ngmin',
      'uglify',
      'rev',
      'usemin'
    ]);
  
    grunt.registerTask('default', ['build']);
  };
  </code></pre>
  
  <p>karma.conf.js:</p>
  
  <pre><code>// Karma configuration
  
  // base path, that will be used to resolve files and exclude
  basePath = '';
  
  // list of files / patterns to load in the browser
  files = [
    JASMINE,
    JASMINE_ADAPTER,
    'app/components/angular/angular.js',
    'app/components/angular-mocks/angular-mocks.js',
    'app/scripts/*.js',
    'app/scripts/**/*.js',
    'test/mock/**/*.js',
    'test/spec/**/*.js'
  ];
  
  // list of files to exclude
  exclude = [];
  
  // test results reporter to use
  // possible values: dots || progress || growl
  reporters = ['progress'];
  
  // web server port
  port = 8080;
  
  // cli runner port
  runnerPort = 9100;
  
  // enable / disable colors in the output (reporters and logs)
  colors = true;
  
  // level of logging
  // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
  logLevel = 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'];
  
  // If browser does not capture in given timeout [ms], kill it
  captureTimeout = 5000;
  
  // Continuous Integration mode
  // if true, it capture browsers, run tests and exit
  singleRun = false;
  </code></pre>
  
  <p>test/spec/controllers/main.js:</p>
  
  <pre><code>'use strict';
  
  describe('Controller: MainCtrl', function () {
  
    // load the controller's module
    beforeEach(module('testApp'));
  
    var MainCtrl,
      scope;
  
    // Initialize the controller and a mock scope
    beforeEach(inject(function ($controller, $rootScope) {
      scope = $rootScope.$new();
      MainCtrl = $controller('MainCtrl', {
        $scope: scope
      });
    }));
  
    it('should attach a list of awesomeThings to the scope', function () {
      expect(scope.awesomeThings.length).toBe(3);
    });
  });'use strict';
  
  describe('Controller: MainCtrl', function () {
  
    // load the controller's module
    beforeEach(module('testApp'));
  
    var MainCtrl,
      scope;
  
    // Initialize the controller and a mock scope
    beforeEach(inject(function ($controller, $rootScope) {
      scope = $rootScope.$new();
      MainCtrl = $controller('MainCtrl', {
        $scope: scope
      });
    }));
  
    it('should attach a list of awesomeThings to the scope', function () {
      expect(scope.awesomeThings.length).toBe(3);
    });
  });
  </code></pre>