Setting up karma, chai, requirejs, chai-jquery

3.6k views Asked by At

I'm close to getting our tests to run with Karma but I'm missing the last step (I think), getting chai-jquery to behave, I've tried two different plugins https://www.npmjs.com/package/karma-chai-jquery and https://www.npmjs.com/package/karma-jquery-chai with no success, even after following the specified order set in their various github issues or readme files.

This is my tests-main.js file

var allTestFiles = [];
var TEST_REGEXP = /(spec|test)\.js$/i;

Object.keys(window.__karma__.files).forEach(function(file) {
    if (TEST_REGEXP.test(file)) {
        // Normalize paths to RequireJS module names.
        allTestFiles.push(file);
    }
});

require.config({

    baseUrl: '/base',

    paths: {
        'chai':             'node_modules/chai/chai',
        'chai-jquery':      'node_modules/chai-jquery/chai-jquery',
        'jquery':           '//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery',
        'underscore':       '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min',
        'sn/sn-underscore': 'static/scripts/sn/sn-underscore',
        'vendor/jquery-ui': '//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min'
    },

    deps: allTestFiles,

    callback: window.__karma__.start
});

This is my karma.conf.js (removed all non-crucial or default options)

// Karma configuration
module.exports = function(config) {
    config.set({
        basePath: '',
        // Can't use chai in here for whatever reason
        frameworks: ['mocha', 'requirejs'],
        files: [
            'static/scripts-test/test-main.js',
            {pattern: 'node_modules/chai/chai.js', included: true},
            {pattern: 'static/scripts-test/**/*.js', included: false},
            {pattern: 'static/scripts/sn/**/*.js', included: false}
        ],
        exclude: [
            'static/scripts/global.js'
        ],
        browsers: ['PhantomJS']
    });
};

This is a "working" spec file, it correctly uses gets the references to chai and jquery, but loading chai-jquery fails every time.

define([
    'chai',
    'jquery',
    'static/scripts/sn/widgets/dismissable'
], function(chai, $) {
    chai.should();
    chai.expect();

    describe('Dismissable', function() {
        var $el = $('</p>'),
            closeBtnSel = '.js-dismissable-close-btn';

        beforeEach(function() {
            $('body').append('<div id="fixtures"></div>');
            $el.appendTo('#fixtures').dismissable({closeFn: 'hide'});
        });

        afterEach(function() {
            $el.remove();
        });

        it('should correctly create the HTML', function() {
            $(closeBtnSel).should.exist;
            $el.should.have.class('dismissable');
        });
    });
});

The error that I get is:

TypeError: 'undefined' is not an object (evaluating '$(closeBtnSel).should.exist')

This is my directory structure:

- static/
  - scripts/
  - scripts-test/
    - test-main.js
- node_modules/
- karma.conf.js

And finally, my package.json

{
  "devDependencies": {
    "chai": "^2.3.0",
    "chai-jquery": "^2.0.0",
    "jquery": "^2.1.4",
    "karma-chai": "^0.1.0",
    "karma-mocha": "^0.1.10",
    "karma-requirejs": "*",
    "mocha": "^2.2.5",
    "requirejs": "^2.1.18",
    "should": "^6.0.1"
  }
}

Some of the errors I usually get:

When changing the order of the frameworks in the karma.conf

    throw error('No provider for "' + name + '"!');
                ^
    Error: No provider for "framework:chai"! (Resolving: framework:chai)

even after installing the plugin

Sometimes I'll get something like this:

Error: Mismatched anonymous define() module: function ($) {
        return function (chai, utils) {
          return chaiJquery(chai, utils, $);
        };
      }

Any help would be greatly appreciated here, I can't wrap my head around this.

EDIT: Small change based on recommendation from Louis

1

There are 1 answers

3
Louis On BEST ANSWER

To install the "should" API, you should do chai.should(), that is, call the function. The line var should = chai.should is not doing anything useful.

It was not initially clear to me whether your issue with should was causing a cascade of problems or if there was something else going on. I've taken a second look and found that there are indeed more problems.

RequireJS Loading from CDN + Karma

There seem to be a bug in Karma there. See this issue, which is still open. There's also that issue which is closed but appears informative. So I've replaced the CDN with a local copy. Otherwise, I get:

ERROR: There is no timestamp for //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js!

Chai

One problem is that you have to decide whether you want to load chai with a script element or through RequireJS. The code in your question tries to do both, which can cause problems. I've decided to have it be loaded by RequireJS. This means that it should have included: false.

chai-jquery

Your test file is not loading chai-jquery and not asking chai to use it. So it is non-existent as far as your code is concerned. The intermittent loading problems you reported may be caused by code in other test files. The require.config call has deps: allTestFiles, but this does not specify any order. RequireJS is free to load the files in allTestFiles in whatever order it wants.

An Example

I took the code you posted in your question as the basis for an example. Obviously, I do not have all the code you have on your side.

Here is the new karma.conf.js:

module.exports = function(config) {
    config.set({
        basePath: '',
        frameworks: ['mocha', 'requirejs'],
        files: [
            'static/scripts-test/test-main.js',
            {pattern: 'node_modules/chai/chai.js', included: false},
            {pattern: 'node_modules/jquery/dist/jquery.min.js',
             included: false},
            {pattern: 'node_modules/chai-jquery/chai-jquery.js',
             included: false},
            {pattern: 'static/scripts-test/**/*.js', included: false},
            {pattern: 'static/scripts/sn/**/*.js', included: false}
        ],
        exclude: [
            'static/scripts/global.js'
        ],
        browsers: ['PhantomJS']
    });
};

The new static/scripts-test/test-main.js which loads jQuery locally:

var allTestFiles = [];
var TEST_REGEXP = /(spec|test)\.js$/i;

Object.keys(window.__karma__.files).forEach(function(file) {
    if (TEST_REGEXP.test(file)) {
        // Normalize paths to RequireJS module names.
        allTestFiles.push(file);
    }
});

require.config({

    baseUrl: '/base',

    paths: {
        'chai':             'node_modules/chai/chai',
        'chai-jquery':      'node_modules/chai-jquery/chai-jquery',
        'jquery':           'node_modules/jquery/dist/jquery.min',
        'underscore':       '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min',
        'sn/sn-underscore': 'static/scripts/sn/sn-underscore',
        'vendor/jquery-ui': '//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min'
    },

    deps: allTestFiles,

    callback: window.__karma__.start
});

A correct test file named static/scripts-test/foo.spec.js, note the use of chai.use(chai_jquery):

define([
    'chai',
    'jquery',
    'chai-jquery',
], function(chai, $, chai_jquery) {
    chai.should();
    chai.use(chai_jquery);

    describe('example', function() {
        it('body should exist', function() {
            $(document.body).should.exist;
        });

        it('#blah should not exist', function() {
            $("#blah").should.not.exist;
        });
    });
});

The code above runs without problem:

WARN [watcher]: Pattern "/tmp/t5/static/scripts/sn/**/*.js" does not match any file.
INFO [karma]: Karma v0.12.37 server started at http://localhost:9876/
INFO [launcher]: Starting browser Chrome
INFO [Chrome 43.0.2357 (Linux 0.0.0)]: Connected on socket Za9vBp9shDedsIhcNn63 with id 48683492
Chrome 43.0.2357 (Linux 0.0.0): Executed 2 of 2 SUCCESS (0.005 secs / 0.002 secs)

I use Chrome as my browser but that's the only difference.