Rafal
Rafal

Reputation: 12619

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.

Upvotes: 10

Views: 8578

Answers (2)

hannes neukermans
hannes neukermans

Reputation: 13257

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

Upvotes: 1

Craig Walker
Craig Walker

Reputation: 51717

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
  })
]

Upvotes: 17

Related Questions