简体   繁体   中英

How can I get code coverage results in my Aurelia app using karma?

I created an Aurelia app using the Aurelia CLI ( au new ) and would like to set up code coverage (preferably with karma-coverage , but if that's not possible I'll use whatever).

I first npm install karma-coverage --save-dev then copy the test.js task over to a cover.js (so that I can run au cover ).

cover.js

import {Server as Karma} from 'karma';
import {CLIOptions} from 'aurelia-cli';
// import project from "../aurelia.json";

export function cover(done) {
  new Karma({
    // This is the same as what's in karma.conf.js after running
    // Except I added the 'src\\**\\*.js' part
    files: [
      'scripts\\vendor-bundle.js',
      {pattern: 'test\\unit\\**\\*.js', included: false},
      'test/aurelia-karma.js',
      'scripts\\app-bundle.js',
      'scripts\\materialize-bundle.js',
      {pattern: 'src\\**\\*.js', included: false}
    ],
    configFile: __dirname + '/../../karma.conf.js',
    singleRun: !CLIOptions.hasFlag('watch'),
    reporters: ['progress', 'coverage'],
    //logLevel: 'debug',
    preprocessors: {
      // [project.unitTestRunner.source]: [project.transpiler.id],  // Is this actually needed? Nothing changes if I add or remove this...
      'src/**/*.js': ['babel', 'coverage']
    },
    coverageReporter: {
      includeAllSources: true,
      reporters: [
        {type: 'html', dir: 'coverage'},
        {type: 'text'}
      ]
    }
  }, done).start();
}

export default cover;

This... gets me somewhere?

控制台输出的<code> au cover </ code>

But I don't think the tests are being linked to the individual src files (they're instead being linked to app-bundle.js ).

Is there any way to get code coverage at the src file level (ie not bundle level) for an Aurelia app?

Other Files of Interest

app.js

export class App {
  constructor() {
    this.message = 'Hello World!';
  }
}

karma.conf.js

"use strict";
const path = require('path');
const project = require('./aurelia_project/aurelia.json');

let testSrc = [
  { pattern: project.unitTestRunner.source, included: false },
  'test/aurelia-karma.js'
];

let output = project.platform.output;
let appSrc = project.build.bundles.map(x => path.join(output, x.name));
let entryIndex = appSrc.indexOf(path.join(output, project.build.loader.configTarget));
let entryBundle = appSrc.splice(entryIndex, 1)[0];
let files = [entryBundle].concat(testSrc).concat(appSrc); console.log(files);

module.exports = function(config) {
  config.set({
    basePath: '',
    frameworks: [project.testFramework.id],
    files: files,
    exclude: [],
    preprocessors: {
      [project.unitTestRunner.source]: [project.transpiler.id]
    },
    'babelPreprocessor': { options: project.transpiler.options },
    reporters: ['progress'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false,
    // client.args must be a array of string.
    // Leave 'aurelia-root', project.paths.root in this order so we can find
    // the root of the aurelia project.
    client: {
      args: ['aurelia-root', project.paths.root]
    }
  });
};

From your terminal screenshot, it looks like you're getting coverage on your individual files src/app.js (12.5%), src/environment.js (0%) and src/main.js (12.5%) in addition to the bundle file. It has to do with that extra line you added including the files that are in src/ .

I suspect that if you go to your coverage directory and view that in the browser, you'll see more detailed results.

I'm not sure about the Aurelia app specifically, but to get individual file coverage, you want to have your tests run against your original files instead of the bundled version and you want that same path to your original files to also be in preprocessors.

files: [
    ...
    'src/**/*.js',
    'path/to/tests/*.spec.js'
    ...
],
preprocessors: {
    'src/**/*.js': ['coverage']
}

This pattern (which you've done) is what tells Karma to load the individual files, and include them in the coverage. At this point, I wouldn't bother loading the bundled application code since you have all the raw stuff being loaded.

Also be sure to load them in the order they're probably bundled in so that you can be sure Karma can initialize the app in the first place.

files: [
    'src/app.js',
    'src/environment.js',
    'src/main.js'
]

And if you are putting your specs named myTest.spec.js next to the files they test, you can use src/!(*.spec).js to make sure that you are including application code without the tests.

I finally got it working, but it required a lot of under-the-hood modifications =\\

First I had to install the following packages

npm install karma-coverage --save-dev
npm install karma-requirejs --save-dev
npm install babel-plugin-istanbul --save-dev

aurelia_project/tasks/cover.js

This is based on test.js .

  • Add requirejs to the list of frameworks (from the karma-requirejs package)
  • Add the individual src/test files (with included: false ) as well as test/aurelia-karma-cover.js , which does the actual require ing of test files.
  • Modified aurelia-karma.js into aurelia-karma-cover.js to not include /test/unit/setup.js (it was giving me trouble with aurelia-browser-pal dependencies)
  • Remove "coverage" from src file preprocessing ( babel-plugin-istanbul will now handle instrumentation of code - see statement at the end for details).
import {Server as Karma} from 'karma';
import {CLIOptions} from 'aurelia-cli';
import project from "../aurelia.json";

export function cover(done) {
  new Karma({
    configFile: __dirname + '/../../karma.conf.js',
    frameworks: [project.testFramework.id, 'requirejs'],
    files: [
      {pattern: 'src\\**\\*.js', included: false},
      {pattern: 'test\\unit\\**\\*.js', included: false},
      // This file actually loads the spec files via require - it's based on aurelia-karma.js
      // but removes setup.js and its dependencies
      'test/aurelia-karma-cover.js'
    ],
    exclude: [
      'src/environment.js',
      'src/main.js',
      'src/resources/index.js'
    ],
    preprocessors: {
      'src/**/*.js': ['babel'],
    },
    reporters: ['progress', 'coverage'],
    singleRun: !CLIOptions.hasFlag('watch'),
    coverageReporter: {
      includeAllSources: true,
      reporters: [
        {type: 'html', dir: 'coverage'},
        {type: 'text'}
      ]
    }
  }, done).start();
}

export default cover;

test/unit/aurelia-karma-cover.js

Just change var allTestFiles = ['/base/test/unit/setup.js']; to var allTestFiles = []; to avoid aurelia-pal-browser dependency errors.

aurelia_project/aurelia.json

Add "istanbul" to the transpiler.options.plugins list if using babel-plugin-istanbul .

* Without babel-plugin-istanbul , code coverage works on post-transpiled code, which adds boilerplate that can't really be tested. This allows you to get to 100% code coverage ;)

@lebolo These were the adjustments I had to make to get things working here:

aurelia_project/tasks/cover.js

Included a constant to vendors path in the beginning of cover function:

const VENDORS_PATH = __dirname + '/../../node_modules/';

Used VENDORS_PATH to include libs I depend on, in files:

files: [
  {pattern: VENDORS_PATH + 'moment/min/moment.min.js', included: false},
  {pattern: 'src/**/*.js', included: false},
  {pattern: 'test/unit/**/*.js', included: false},
  'test/aurelia-karma-cover.js'
]

Included test files in preprocessors:

preprocessors: {
  'src/**/*.js': ['babel'],
  'test/unit/**/*.js': ['babel']
}

test/unit/aurelia-karma-cover.js

Change the way url is built in requirejs.load function:

url = '/base/' + url; => url = ['/base', root, url].join('/');

Included one more function to config requirejs paths and calling it after patchRequireJS() call:

  function configRequire() {
    var VENDORS_PATH = '../node_modules/';

    requirejs.config({
      paths: {
        'moment': VENDORS_PATH + 'moment/min/moment.min'
      }
    });
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM