简体   繁体   中英

Coverage reports with karma and a mix of javascript and typescript src files

I have a project where I use webpack for development/testing and karma as my test runner. This project has source files written half in js and half in ts/tsx. The test suite is written completely in js. I currently use karma-coverage, which shows coverage reports for all my js source files, but it does not support typescript files. All my tests run, there is no problem there, I just would like coverage reports for all my test files. Can anyone point me in the right direction?

Here is my karma.conf.js if this helps.

'use strict';

const webpackCfg = require('./webpack.config')('test');

module.exports = function karmaConfig(config) {

  config.set({
    browsers: ['Chrome'],
    files: [
      'test/loadtests.js'
    ],
    port: 8080,
    captureTimeout: 60000,
    frameworks: [
      'mocha',
      'chai',
      'sinon'
    ],
    client: {
      mocha: {}
    },
    singleRun: true,
    reporters: ['mocha', 'coverage', 'junit'],
    mochaReporter: {
      output: 'autowatch'
    },
    preprocessors: {
      'test/loadtests.js': ['webpack', 'sourcemap']
    },
    webpack: webpackCfg,
    webpackServer: {
      noInfo: true
    },
    junitReporter: {
      outputDir: 'coverage',
      outputFile: 'junit-result.xml',
      useBrowserName: false
    },
    coverageReporter: {
      dir: 'coverage/',
      watermarks: {
        statements: [70, 80],
        functions: [70, 80],
        branches: [70, 80],
        lines: [70, 80]
      },
      reporters: [
        { type: 'text' },
        {
          type: 'html',
          subdir: 'html'
        },
        {
          type: 'cobertura',
          subdir: 'cobertura'
        },
        {
          type: 'lcovonly',
          subdir: 'lcov'
        }
      ]
    }
  });
};

And the relevant part of my webpack test config

  {
      devtool: 'inline-source-map',
      externals: {
        cheerio: 'window',
        'react/lib/ExecutionEnvironment': true,
        'react/addons': true,
        'react/lib/ReactContext': true,
      },
      module: {
        preLoaders: [
          {
            test: /\.(js|jsx)$/,
            loader: 'isparta-loader',
            include: [
              this.srcPathAbsolute
            ]
          }
        ],
        loaders: [
          {
            test: /\.cssmodule\.css$/,
            loaders: [
              'style',
              'css?modules&importLoaders=1&localIdentName=[name]-[local]-[hash:base64:5]'
            ]
          },
          {
            test: /^.((?!cssmodule).)*\.css$/,
            loader: 'null-loader'
          },
          {
            test: /\.(sass|scss|less|styl|png|jpg|gif|mp4|ogg|svg|woff|woff2)$/,
            loader: 'null-loader'
          },
          {
            test: /\.json$/,
            loader: 'json'
          },
          {
            test: /\.ts(x?)$/,
            exclude: /node_modules/,
            loader: ['babel', 'ts-loader']
          },
          {
            test: /\.(js|jsx)$/,
            loader: 'babel-loader',
            query: {
              presets: ['airbnb']
            },
            include: [].concat(
              this.includedPackages,
              [
                this.srcPathAbsolute,
                this.testPathAbsolute
              ]
            )
          }
        ]
      },
      plugins: [
        new webpack.DefinePlugin({
          'process.env.NODE_ENV': '"test"'
        })
      ]
    }

After a couple days of soul and google searching amongst hundreds of browser tabs, I have found a working solution. This is using TypeScript 2.x and Webpack 2.x. test.js is my entry point. It could just as easily be test.ts (and it will be eventually). In that entry point, I load my *.spec.js and *.spec.ts files. And then those files import whichever source they need to test from. I have put all the webpack config in the karma.conf.js so it's easier to see:

let myArgs = require('yargs').argv;
let path = require('path');
let webpack = require('webpack');

module.exports = function(config) {
  const REPORTS_PATH = myArgs.reportsPath ? myArgs.reportsPath :path.join(__dirname, 'build');

  config.set({
    basePath: '',

    frameworks: ['jasmine', 'es6-shim'],

    files: [
      './test.js'
    ],

    exclude: [],

    reporters: ['progress', 'spec', 'coverage', 'junit', 'coverage-istanbul'],

    preprocessors: {
      './test.js': ['webpack', 'sourcemap']
    },

    webpackServer: {
       noInfo: true // prevent console spamming when running in Karma!
    },

    webpack: {
      devtool: 'inline-source-map',
      resolve: {
        modules: [
          path.resolve('./node_modules'),
          path.resolve('./')
        ],
        extensions: ['.js', '.ts', '.css', '.scss']
      },
      plugins: [
        new webpack.ProvidePlugin({
           $: "jquery",
           jQuery: "jquery",
          "window.jQuery": "jquery"
        })
      ],
      module: {
        rules: [
          {
            enforce: 'pre',
            test: /\.js$/,
            use: 'source-map-loader',
            exclude: [/node_modules/]
          },
          {
            test: /\.ts$/,
            use: [{
              loader: 'awesome-typescript-loader',
              options: {
                module: 'commonjs'
              },
            }]
          },
          {
            test: /\.js$/,
            use: [{
            loader: 'awesome-typescript-loader',
              options: {
                entryFileIsJs: true,
                transpileOnly: true
              }
            }],
            exclude: [/node_modules/],
          },
          {
            enforce: 'post',
            test: /\.(js|ts)$/,
            use: [{
              loader: 'istanbul-instrumenter-loader',
              options: {
                esModules: true
              }
            }],
            exclude: [/node_modules/, /\.spec\.(js|ts)$/, /test/]
          },
          { test: /\.html/, use: 'raw-loader' },
          { test: /\.(s)?css$/, use: 'null-loader' },
          { test: /\.(png|jpg|jpeg|gif|svg|pdf)$/, use: 'null-loader' },
          { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, use: 'null-loader' },
          { test: /\.(ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/, use: 'null-loader' },
          { test: /\.json$/, use: 'null-loader' }
        ]
      }
    },

    coverageReporter: {
      type: 'in-memory'
    },

    coverageIstanbulReporter: {
      //TODO: Figure out why the 'html' reporter blows up with istanbul-reports (something with absolute path copying files)
      reports: ['text-summary', 'cobertura'],
      // base output directory
      dir: REPORTS_PATH,
      fixWebpackSourcePaths: true,
      'report-config': {
        cobertura: {
          file: 'coverage.xml'
        },
        'text-summary': {
          file: null
        }
      }
    },

    junitReporter: {
      outputDir: `${REPORTS_PATH}/junit/`,
      outputFile: 'jasmine-results.xml'
    },

    // Hide webpack build information from output
    webpackMiddleware: {
      stats: {
        chunkModules: false,
        colors: true
      },
      noInfo: 'errors-only'
    },

    colors: true,
    logLevel: config.LOG_ERROR,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false,
    autoWatchBatchDelay: 400
  });
};

So, the key pieces here are awesome-typescript-loader , karma-coverage-istanbul-reporter , source-map-loader , and in the tsconfig.json , you want to set these in compilerOptions :

"inlineSourceMap": true,
"sourceMap": false,

I indicated a TODO about the html report. It DOES work but I couldn't get it to output to a custom directory (subdir) with TypeScript files as a part of it. JavaScript only worked fine. Could be a windows-specific problem with istanbul-reports . If you add html to the reports array under coverageIstanbulReporter , you should see it in your project dir but may have problems putting it in REPORTS_PATH .

It's also worth noting that I had a lot of luck using karma-remap-coverage instead of karma-coverage-istanbul-reporter but the former would not correctly generate cobertura reports for coverage which is what I needed for Jenkins.

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