Mocha unit tests running with Karma - done() is not defined

14,345

Solution 1

In Mocha, the done callback is for it, before, after, beforeEach, afterEach. So:

describe('nothing', function() {
    it('a silly test', function(done) {
        var note = new Note;
        note.should.not.eql(32);
        done();
    });
});

Here's the doc.

Solution 2

The test you are running in that example doesn't require the done() callback. It is not asynchronous. An example of when the done callback is need....

describe('Note', function() {
    it('can be retrieved from database', function(done) {
        var note = new Note();
        cb = function(){
           note.contents.should.eql("stuff retrieved from database");
           done()
        }
        //cb is passed into the async function to be called when it's finished
        note.retrieveFromDatabaseAsync(cb)
    });
});

Your test should not have a done callback

describe('nothing', function() {
    it('umm...', function() {
        var note = new Note;
        note.should.not.eql(32);
    });

});

Only the 'it' function provides a done callback. describe does not. Your problem does not rest with karma. Your mocha tests are not defined correctly.

Solution 3

Holy %$#@!

I would never in a million years have thought this would barf:

describe('nothing', function(done) {
    it('umm...', function() {
        var note = new Note;
        note.should.not.eql(32);
    });
    done(); // throws error that undefined is not a function
});

But this works just fine:

describe('nothing', function(done) {
    it('umm...', function() {
        var note = new Note;
        note.should.not.eql(32);
    });
    setTimeout(function() {
        done();  // MAGIC == EVIL.
    }, 1000);
});
Share:
14,345
Jason Boyd
Author by

Jason Boyd

Updated on June 05, 2022

Comments

  • Jason Boyd
    Jason Boyd about 2 years

    I'm trying to get tests written with Mocha to work running Karma, and they sort of work, but I cannot use the done() method to implement async tests, which essentially makes the tools useless to me. What am I missing?

    karma.conf.js

    module.exports = function(config) {
      config.set({
        basePath: '../..',
        frameworks: ['mocha', 'requirejs', 'qunit'],
        client: {
            mocha: {
                ui: 'bdd'
            }
        },
        files: [
          {pattern: 'libs/**/*.js', included: false},
          {pattern: 'src/**/*.js', included: false},
          {pattern: 'tests/mocha/mocha.js', included: false},
          {pattern: 'tests/should/should.js', included: false},
          {pattern: 'tests/**/*Spec.js', included: false},
          'tests/karma/test-main.js'
        ],
        exclude: [
          'src/main.js'
        ],
        // test results reporter to use
        // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
        reporters: ['progress', 'dots'],
        port: 9876,
        colors: true,
        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
        logLevel: config.LOG_WARN,
        autoWatch: true,
        // Start these browsers, currently available:
        // - Chrome
        // - ChromeCanary
        // - Firefox
        // - Opera (has to be installed with `npm install karma-opera-launcher`)
        // - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`)
        // - PhantomJS
        // - IE (only Windows; has to be installed with `npm install karma-ie-launcher`)
        browsers: ['Chrome'],
        // 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
      });
    };
    

    test-main.js (configuring RequireJS)

    var allTestFiles = [];
    var pathToModule = function(path) {
      return path.replace(/^\/base\//, '../').replace(/\.js$/, '');
    };
    
    Object.keys(window.__karma__.files).forEach(function(file) {
      if (/Spec\.js$/.test(file)) {
        // Normalize paths to RequireJS module names.
        allTestFiles.push(pathToModule(file));
      }
    });
    
    require.config({
      // Karma serves files under /base, which is the basePath from your config file
      baseUrl: '/base/src',
      paths: {
        'should': '../tests/should/should',
        'mocha': '../tests/mocha/mocha',
        'pubsub': '../libs/pubsub/pubsub',
        'jquery': '../libs/jquery/jquery-1.10.2',
        'jquery-mobile': '//code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min'
      },
      // dynamically load all test files
      deps: allTestFiles, 
      // we have to kickoff jasmine, as it is asynchronous
      callback: window.__karma__.start
    });
    

    tests/fooSpec.js

    define(['music/note'], function(Note) {
    
    describe('nothing', function(done) {
        it('a silly test', function() {
            var note = new Note;
            note.should.not.eql(32);
        });
        done();
    });
    ...
    

    Though this is a contrived example, it succeeds if I remove the done() call. As it is, I get:

    Uncaught TypeError: undefined is not a function
    at /Library/WebServer/Documents/vg/tests/mocha/fooSpec.js:8
    

    This is the done() line. How/why is this not defined? I'm not understanding where else to configure Mocha (or with what options). Is there some sort of global namespace or meta-programming magic causing RequireJS to interfere with Mocha?

    I'm running the tests in Chrome 33 on OS X 10.9.2, in case that is at all relevant. I've killed a ton of time on this and am ready to give up on automated testing :( -- had similar brick walls with QUnit/Karma/RequireJS and have not been able to find any alternative to successfully automate tests. I feel like an idiot.