Search code examples
javascriptnode.jsjasminejasmine-node

jasmine-nodejs and using done() to complete asynch tests


I seem to be having a problem setting up my unit tests for my NodeJS app and then running them with Jasmine. The problem comes in using the done function of Jasmine. Whenver I include the done function in my test, I get an error that reads: Warning: Cannot read property 'clearTimeout' of undefined Use --force to continue. I'm pretty sure I'm not doing something right, but what that something is continues to elude me.

My Gruntfile.js:

module.exports = function(grunt){
    // Load grunt tasks automatically
    require('load-grunt-tasks')(grunt);

    grunt.initConfig({
        // Make sure code styles are up to par and there are no obvious mistakes
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            all: [
                'Gruntfile.js',
                'app/scripts/Directives/**/*.js',
                'app/scripts/Services/**/*.js',
                'app/scripts/app.js'
            ]
        },

        // Empties folders to start fresh
        clean: {
            options: { force: true },
            dist: {
                files: [
                    {
                        dot: true,
                        src: [
                            '/dist/*'
                        ]
                    }
                ]
            },
            coverage: {
                files: [
                    {
                        dot: true,
                        src: [
                            '.coverage/'
                        ]
                    }
                ]
            }
        },

        // Copies remaining files to places other tasks can use
        copy: {
            dist: {
                files: [
                    {
                        expand: true,
                        dot: true,
                        cwd: '<%= yeoman.app %>',
                        dest: '<%= yeoman.dist %>',
                        src: [
                            '*.{ico,png,txt,json,js,shtml,template}',
                            'images/{,*/}*.{webp}',
                            'fonts/*',
                            'images/**/*.svg',
                            'api-documentation/**/**/*',
                            'api-explorer/**/*',
                            'styles/*.{ttf,woff,svg,css}',
                            'docs/**/*',
                            'template/**/*.{htm,html}',
                            'locale/*',
                            'config/*'
                        ],
                        rename: function(dest, src){

                            if(src.indexOf('customizations.html.template') !== -1 ||
                                src.indexOf('customizations.js.template') !== -1){
                                console.log( dest + '/' + src.replace('.template', ''));
                                return dest + '/' + src.replace('.template', '');
                            }

                            return dest + '/' + src;
                        }
                    },
                    {
                        expand: true,
                        cwd: '.tmp/images',
                        dest: '<%= yeoman.dist %>/images',
                        src: [
                            'generated/*'
                        ]
                    },
                    {
                        expand:true,
                        cwd: '.tmp/styles',
                        dest: '<%= yeoman.dist %>/styles',
                        src:['customer.css']
                    }
                ]
            }
        },

        // Test settings
        karma: {
            unit: {
                configFile: 'karma.conf.js',
                singleRun: true,
                reporters: ['dots']
            },
            coverage: {
                configFile: 'karma.coverage.conf.js',
                singleRun: true,
                reporters: ['spec', 'coverage'],
                coverageReporter: {
                    type: 'html',
                    dir: '.coverage/'
                }
            },
            node:{
                configFile:'karma.node.conf.js',
                singleRun:true,
                reporters:['spec', 'coverage'],
                coverageReporter: {
                    type: 'html',
                    dir: '.nodeCoverage/'
                }
            }
        },

        open : {
            coverage : {
                path: 'http://127.0.0.1:8888/src'
            },
            covReport: {
                path: 'http://localhost:63342/ClassroomLibrary/' + grunt.file.expand('.coverage/Phantom*/index.html')
            }
        },

        jasmine_nodejs:{
            options:{
                specNameSuffix:'node.spec.js',
                reporters:{
                    console:{
                        colors:true,
                        cleanStack:1,
                        verbosity:4,
                        listStyle:'indent',
                        activity:false
                    }
                }
            },
            all:{
                options:{
                    useHelpers:true
                },
                specs:[
                    'tests/Node/**'
                ]
            }
        },
        nodemon:{
            tests:{
                script:'app/index.js'
            }
        },
        concurrent:{
            nodeTests:['nodemon', 'jasmine_nodejs']
        },
        run_node:{
            start:{
                files:{src:['app/index.js']}
            }
        },
        stop_node:{
            stop:{
                files:{src:['app/index.js']}
            }
        }
    });

    grunt.loadNpmTasks('grunt-jasmine-nodejs');
    grunt.loadNpmTasks('grunt-nodemon');
    grunt.loadNpmTasks('grunt-concurrent');
    grunt.loadNpmTasks('grunt-run-node');

    grunt.registerTask('test', [
        'karma:unit'
    ]);

    grunt.registerTask('coverage', [
        'clean:coverage',
        'karma:coverage',
        'open:covReport'
    ]);

    grunt.registerTask('nodeTests', ['concurrent:nodeTests']);
    grunt.registerTask('testingNode', ['run_node', 'jasmine_nodejs', 'stop_node']);
    //grunt.registerTask('karmaNode', ['run_node', 'karma:node', 'stop_node']);
};

The test suite in question:

var request = require('http');
describe('Node server', function(){
    'use strict';

    //http://www.randomjavascript.com/2012/12/using-jasmine-node-to-test-your-node.html
    var serverUrl = 'http://127.0.0.1:2425';

    it('should respond to /', function(done){
        request.get(serverUrl, function(response){
            expect(response.statusCode).toBe(200);
            done();
        });
    });
});

Obviously I've tried a couple of different ways to get this to work. Running them via Karma was more trouble than it was worth (I left that config in there to show what I have tried.) While I have been happy with the output of nodeMon and jasmine-nodejs I still can't get the whole thing to run front to back because without the done function things hang just like you would expect them to. It is supposed to be just THERE but for me it isn't. My package.json contains:

{
  "name": "myProject",
  "version": "0.0.1",
  "dependencies":{},
  "devDependencies": {
    "karma": "~0.13",
    "karma-coverage": "~0.5",
    "karma-phantomjs-launcher": "~1.0",
    "karma-ng-html2js-preprocessor": "~0.1",
    "phantomjs-prebuilt": "~2.1",
    "grunt": "~1.0",
    "grunt-contrib-clean": "~0.7",
    "grunt-contrib-uglify": "~0.11",
    "grunt-contrib-concat": "~0.5",
    "grunt-contrib-copy": "~1.0",
    "grunt-concurrent":"~2.3",
    "grunt-jasmine-nodejs":"~1.5",
    "grunt-jasmine-node-coverage":"0.5.0",
    "grunt-open":"~0.2",
    "grunt-nodemon":"~0.4",
    "grunt-run-node":"~0.1",
    "grunt-karma": "~0.12",
    "jasmine-core": "~2.4",
    "jasmine-node":"~1.14",
    "karma-jasmine": "~0.3",
    "karma-jasmine-matchers": "~2.0",
    "karma-spec-reporter":"~0.0",
    "karma-requirejs":"~1.0",
    "load-grunt-tasks": "~3.4",
    "uglify-js": "~2.6",
    "grunt-sass": "~1.1",
    "jshint":"~2.9"
  },
  "engines": {
    "node": ">=0.12.0"
  },
  "scripts": {
    "global": "npm i karma-cli grunt-cli -g"
  }
}

Can someone please tell me where the process is missing what it needs?


Solution

  • One thought--can you confirm the version of Jasmine you're actually using matches what you're intending to use? I think the 'done' callback was added in 2.0, so I could see this error occurring on an older version...

    EDIT: you're using the "jasmine-node" package which is version 1.3.1, so that feature won't be available.