Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure karma so typescript source files would be debuggable

I've downloaded a seed project Angular2 Webpack Starter and got it up and running without an issue. One inconvenience that I have with it is debugging source files under unit tests. All *.spec.ts files are loaded into browser and debugable so map files are generated for them at least. When I step into a source file under test I get something like this:

Source file in browser

karma config:

module.exports = function(config) {
var testWebpackConfig = require('./webpack.test.js');

config.set({
    basePath: '',
    frameworks: ['jasmine'],
    exclude: [ ],
    files: [ { pattern: './config/spec-bundle.js', watched: false } ],
    preprocessors: { './config/spec-bundle.js': ['coverage', 'webpack', 'sourcemap'] },
    webpack: testWebpackConfig,
    coverageReporter: {
      dir : 'coverage/',
      reporters: [
        { type: 'text-summary' },
        { type: 'json' },
        { type: 'html' }
      ]
    },
webpackServer: { noInfo: true },
reporters: [ 'mocha', 'coverage' ],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: [
  'Chrome'
],
singleRun: false
});
};

webpack.test.js:

const helpers = require('./helpers');
const ProvidePlugin = require('webpack/lib/ProvidePlugin');
const DefinePlugin = require('webpack/lib/DefinePlugin');
const ENV = process.env.ENV = process.env.NODE_ENV = 'test';
module.exports = {
    devtool: 'inline-source-map',
    resolve: {
        extensions: ['', '.ts', '.js'],
        root: helpers.root('src'),
    },
    module: {
    preLoaders: [
      {
        test: /\.ts$/,
        loader: 'tslint-loader',
        exclude: [helpers.root('node_modules')]
      },
      {
        test: /\.js$/,
        loader: 'source-map-loader',
        exclude: [
            helpers.root('node_modules/rxjs'),
            helpers.root('node_modules/@angular2-material'),
            helpers.root('node_modules/@angular')
      ]}
   ],
loaders: [
{
    test: /\.ts$/,
    loader: 'awesome-typescript-loader',
    query: {
      compilerOptions: {
          removeComments: true
      }
    },
    exclude: [/\.e2e\.ts$/]
  },
  { test: /\.json$/, loader: 'json-loader', exclude: [helpers.root('src/index.html')] },
  { test: /\.css$/, loaders: ['to-string-loader', 'css-loader'], exclude: [helpers.root('src/index.html')] },
  { test: /\.html$/, loader: 'raw-loader', exclude: [helpers.root('src/index.html')] }
],
postLoaders: [
{
    test: /\.(js|ts)$/, loader: 'istanbul-instrumenter-loader',
    include: helpers.root('src'),
    exclude: [
      /\.(e2e|spec)\.ts$/,
      /node_modules/
    ]
  }
]
},
plugins: [
new DefinePlugin({
  'ENV': JSON.stringify(ENV),
  'HMR': false,
  'process.env': {
    'ENV': JSON.stringify(ENV),
    'NODE_ENV': JSON.stringify(ENV),
    'HMR': false,
  }
}),
],
tslint: {
    emitErrors: false,
    failOnHint: false,
    resourcePath: 'src'
  },
node: {
    global: 'window',
    process: false,
    crypto: 'empty',
    module: false,
    clearImmediate: false,
    setImmediate: false
}
};

spec-bundle.js:

Error.stackTraceLimit = Infinity;
require('core-js/es6');
require('core-js/es7/reflect');
require('ts-helpers');
require('zone.js/dist/zone');
require('zone.js/dist/long-stack-trace-zone');
require('zone.js/dist/jasmine-patch');
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');
require('zone.js/dist/sync-test');
require('rxjs/Rx');
var testing = require('@angular/core/testing');
var browser = require('@angular/platform-browser-dynamic/testing');
testing.setBaseTestProviders(
  browser.TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
  browser.TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS
);
var testContext = require.context('../src', true, /\.spec\.ts/);
function requireAll(requireContext) {
  return requireContext.keys().map(requireContext);
}
var modules = requireAll(testContext);

This configuration is as in starter package with minor if any modifications. Could you tell me how to modify this configuration so the .ts source files would be debugable with coverage statistics.

like image 733
Rafal Avatar asked Jul 13 '16 06:07

Rafal


People also ask

How do I create a karma config file?

In order to serve you well, Karma needs to know about your project in order to test it and this is done via a configuration file. The easiest way to generate an initial configuration file is by using the karma init command. This page lists all of the available configuration options.

What does it mean to set the singleRun attribute to true located in the Karma Conf js file?

Setting singleRun: false assumes that you are explicitly start the karma-client manually. This means that you start karma (technically the karma-server), then go to another terminal and type karma run . Setting singleRun: true in your karma configuration will call karma run for you.

What is karma config js file?

Most of the framework adapters, reporters, preprocessors and launchers needs to be loaded as plugins. The Karma configuration file can be written in JavaScript or CoffeeScript and is loaded as a regular Node. js module. Within the configuration file, the configuration code is put together by setting module.

What is karma typescript?

Karma ❤️ Typescript. Run unit tests written in Typescript with full type checking, seamlessly without extra build steps or scripts.


2 Answers

I had a similar issue with my project (which isn't the Angular2 Webpack Starter, but I believe has the same cause.)

WebPack, by default, doesn't pass source maps up to Karma unless the file extension is .js (or .jsx if you're using React). In a setup like this one, Karma+WebPack just transpiles the .ts files (or .tsx) straight from TypeScript to JavaScript and serves them under the same file name.

I found a solution that worked for me on the GitHub Issues page for karma-webpack. The trick is to inject webpack.SourceMapDevToolPlugin with a widened file filter into the webpack config. For you, that should look something like this:

var webpack = require('webpack');
// in your config.set:
plugins: [
  // existing plugins go here
  new webpack.SourceMapDevToolPlugin({
    filename: null, // if no value is provided the sourcemap is inlined
    test: /\.(ts|js)($|\?)/i // process .js and .ts files only
  })
]
like image 121
Craig Walker Avatar answered Oct 10 '22 19:10

Craig Walker


You need to comment out Istanbul loader inside your webpack.test.config.js, like this

    // {
    //   enforce: 'post',
    //   test: /\.(js|ts)$/,
    //   loader: 'istanbul-instrumenter-loader',
    //   include: helpers.root('src'),
    //   exclude: [
    //     /\.(e2e|spec)\.ts$/,
    //     /node_modules/
    //   ]
    // }

then simply run:

 npm run watch:test
like image 25
hannes neukermans Avatar answered Oct 10 '22 19:10

hannes neukermans