Using Karma to test StealJS

Is there an example anywhere of using Karma to test a StealJS app?

Hey blink1073, unfortunately I don’t know of an example. Most of our projects use Testee and not Karma. However setting up Karma with Steal should be very similar to how it is used with RequireJS: http://karma-runner.github.io/0.13/plus/requirejs.html

I think the key thing is likely that you want to start Karma after Steal has finished loading. To do that you can use:

steal.done().then(function(){
  if(window.__karma__) {
    window.__karma__.start();
  }
});

How/where you add this bit of code is unfortunately beyond my knowledge of Karma. I hope this helps though.

@blink1073 I set up a simple project with Karma & StealJS. Like @matthewp mentioned, it’s a lot like setting up Karma with RequireJS. The biggest difference is that you’ll need to manually set Karma to run asynchronously. This is normally done by the karma-requirejs adapter.

I used karma init to create a base karma.conf.js file with most of the default values. Then I added file patterns for all of the files that would be loaded by Steal. These are set as included: false so that Karma will not create script tags for them. I then added Steal and karma.bootstrap.js. karma.bootstrap.js will run the code @matthewp gave above, you can call it whatever you want. It’s discussed more below.

Here is what the karma configuration looks like in my project:

module.exports = function(config) {
  config.set({
    basePath: '',
    frameworks: ['qunit'],
    files: [
      { pattern: 'src/**/*.js', included: false },
      { pattern: 'src/**/*.stache', included: false },
      { pattern: 'src/**/*.less', included: false },
      { pattern: 'node_modules/steal/**/*.js', included: false },
      { pattern: 'node_modules/can/**/*.js', included: false },
      { pattern: 'node_modules/funcunit/**/*.js', included: false },
      { pattern: 'node_modules/can-fixture/**/*.js', included: false },
      { pattern: 'node_modules/done-css/**/*.js', included: false },
      { pattern: 'node_modules/can-connect/**/*.js', included: false },
      { pattern: 'node_modules/jquery/**/*.js', included: false },
      { pattern: 'node_modules/**/package.json', included: false },
      { pattern: 'package.json', included: false },
      'node_modules/steal/steal.js',
      'karma.bootstrap.js'
    ],
    exclude: [ ],
    preprocessors: { },
    reporters: ['progress'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    browsers: ['Firefox'],
    singleRun: true,
    concurrency: Infinity
  })
};

The karma.bootstrap.js file just needs to overwrite the window.__karma__.loaded function. This function normally starts Karma, but we need it to configure Steal and then start Karma once Steal is done. Here’s what karma.bootstrap.js looks like in my project:

window.__karma__.loaded = function() {
  System.main = 'src/test/';

  steal.done().then(function(){
    if(window.__karma__) {
      window.__karma__.start();
    }
  });
};

The only other thing I saw was that using steal-qunit would cause a warning about QUnit.start() being called multiple times, so I changed my project to use regular QUnit instead.

2 Likes

Thanks @matthewp and @phillipskevin, the bootstrap override worked nicely.

Further to the posts above, if you want to load all your tests dynamically, there are a couple of changes needed. First the karma.bootstrap.js becomes:

window.__karma__.loaded = function() {
    System.main = 'tests/include-all-tests';
};

include-all-tests.js is:

var tests = [];
for (var file in window.__karma__.files) {
    if (window.__karma__.files.hasOwnProperty(file)) {
        if (/base\/tests\/.*-test\.js$/.test(file)) {
            tests.push(file.substr(6));
        }
    }
}

tests[tests.length] = function() {
    if(window.__karma__) {
        window.__karma__.start();
    }
};

steal.apply(null, tests);

Be sure to make the appropriate changes to the path to your tests and the Spec qualifier (I use -test instead of Spec). Note, you need to strip off the ‘/base/’ from the beginning of each test file name.

@coliphant @phillipskevin I am getting a following error

“Uncaught ReferenceError: System is not defined” at karma.bootstrap.js:2

The above error comes up at line “System.main = ‘tests/include-all-tests’;”

Any idea what could be wrong? Please let me know once you get a chance. Thanks.

The way Karma handles files has changed. Here is an updated karma-bootsrap.js that runs (though still doesn’t work):

const getPortSync = require('get-port-sync');

var port = getPortSync()

module.exports = function(config) {
  config.set({
    frameworks: ['mocha'],
    autoWatch: false,
    basePath: '../',
    browsers: ['Chrome'],
    port: port,
    singleRun: true,
    files: [
      { pattern: 'src/**/*.js', included: false },
      { pattern: 'src/**/*.stache', included: false },
      { pattern: 'src/**/*.less', included: false },
      { pattern: 'node_modules/steal/ext/**/*.js', included: false },
      { pattern: 'node_modules/steal-conditional/**/*.js', included: false },
      { pattern: 'node_modules/can*/**/*.js', included: false },
      { pattern: 'node_modules/mocha/**/*.js', included: false },
      { pattern: 'node_modules/chai/**/*.js', included: false },
      { pattern: 'node_modules/done-css/**/*.js', included: false },
      { pattern: 'node_modules/jquery/**/*.js', included: false },
      { pattern: 'node_modules/**/package.json', included: false },
      { pattern: 'package.json', included: false },
      'node_modules/steal/steal.js',
      'karma.bootstrap.js'
    ]
  });
};

Notice the change in steal. You can’t import it twice so once is just the extensions and the other is actually included.
Trying to debug karma.bootstrap but it looks like it doesn’t run

As discussed on slack, I didn’t find how to make steal works with karma, it seems a steal preprocessor for karma is needed to have them work together.