karma.conf.js automatic file ordering?

All we need is an easy explanation of the problem, so here it is.

I have a large angularjs project ordered by features. I’d like to setup unit testing but I’m having trouble getting the karma.conf.js file ordering setup.

I tried specifying a simple glob pattern like **/*.js but many of my modules failed to load due to the ordering that they’re included in Karma when ran. As I understand, it’s alphabetical, first match.

I was able to resolve this by manually figuring out the ordering by doing something like this:

// list of files / patterns to load in the browser
files: [
  // External scripts
  'bower_components/angular/angular.js',
  'bower_components/angular-mocks/angular-mocks.js',
  'bower_components/angular-cookies/angular-cookies.js',
  'bower_components/angular-resource/angular-resource.js',
  'bower_components/angular-route/angular-route.js',

  // NOTE: ORDER IS IMPORTANT
  // Modules: load module first, then all controllers, services, etc
  'scripts/module1/module1.js',
  'scripts/module1/**/*.js',
  'scripts/module2/module2.js',
  'scripts/module2/**/*.js',

  // Load overall app module last
  'scripts/app.js',

  // Load mocks and tests
  'test/mock/**/*.js',
  'test/spec/**/*.js'
],

This seems like it will be cumbersome to maintain over time as new modules are added. Is there a way to automatically resolve the ordering?

Note: One possible solution I was thinking was to concat all the files together but I googled to see if others are doing this and found no examples.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

I think you may look into different solutions here, depending on how you want to manage your project.

Solution n.1

Use AMD/RequireJS: do not load your modules all at once but just require them when you need.
Sometimes it may not fit your needs tough making the project over complicated, so look below.

Note: this is IMHO the most elegant solution and karma does support requireJS.

Solution n.2

Create a namespace where you append all your stuff and start them when the DOM is ready (usually pretty quick, but it really depends on how much scripts you load)

// module A
// Something like this should be fine
(function(){
  window.MyNamespace = window.MyNamespace || {};
  // append things to the namespace...
})();

// module B
(function(){
  window.MyNamespace = window.MyNamespace || {};
  // append things to the namespace...
})();

// This is very rough but it should give the idea
window.ondomready = MyNamespace.start;

Note: while this may work you have to fiddle a bit with your project to change the structure accordingly.

I would go for the one above unless you really hates requireJS and all the modules stuff.

Solution n.3

Programmatically order your Karma files: I wrote about it in this answer here.

Note: this is the less mantainable of the options.

Method 2

If this

  // Modules: load module first, then all controllers, services, etc
  'scripts/module1/module1.js',
  'scripts/module1/**/*.js',
  'scripts/module2/module2.js',
  'scripts/module2/**/*.js',

could instead force the same filenaming convention on the module-declaration file, to be this

  // Modules: load module first, then all controllers, services, etc
  'scripts/module1/moduleDeclaration.js',
  'scripts/module1/**/*.js',
  'scripts/module2/moduleDeclaration.js',
  'scripts/module2/**/*.js',

Then you could do this

  // Modules: load module first, then all controllers, services, etc
  'scripts/**/moduleDeclaration.js',
  'scripts/**/*.js',

I do something similar, though I do break out interfaces & types between moduleDeclaration and “the rest of it”.

Method 3

I use browserify and i have no prblems with it, here is my configuration:

module.exports = function(config) {
  config.set({

    basePath: '',
    frameworks: ['browserify', 'jasmine'],
    files: [
      'bower_components/angular/angular.js',
      'bower_components/angular-mocks/angular-mocks.js',
      'dev/**/*Spec.js'
    ],
    exclude: [
    ],
    browserify: {
      watch: false,
      debug: true
    },
    preprocessors: {
      'dev/**/*Spec.js': ['browserify']
    },
    reporters: ['progress'],
    port: ****,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    browsers: ['Chrome'],
    singleRun: true
  });
};

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply