karma.conf.js automatic file ordering?

2019-03-27 19:35发布

问题:

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.

回答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.



回答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".



回答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
  });
};