Search code examples
typescriptistanbulnyc

nyc runtime coverage with cucumber


I am trying to get coverage for my e2e tests written in cucumber/TS, but my test report is never able to map back to my source files.

The report is just a list of directories, and clicking into individual *.ts files yields a stacktrace (***'d out my user/repo name):

Unable to lookup source: /Users/***/dev/git/***/dist/webpack:/src/gql/index.ts(ENOENT: no such file or directory, open '/Users/***/dev/git/***/dist/webpack:/src/gql/index.ts')
Error: Unable to lookup source: /Users/***/dev/git/***/dist/webpack:/src/gql/index.ts(ENOENT: no such file or directory, open '/Users/***/dev/git/***/dist/webpack:/src/gql/index.ts')

What I'm trying to do:

  1. Run instrumented application with TypeScript sourcemaps
  2. Run my tests externally against this application
  3. Stop application and generate coverage report for original TS code

My setup is as follows,

  • node: v9.4.0
  • webpack: ^4.23.0,
  • typescript: ~3.1.6

tsconfig:

{
    "compilerOptions": {
    "rootDir": "./src",
    "module": "commonjs",
    "target": "es6",
    "sourceMap": true,
    "outDir": "./dist",
    "noEmitOnError": true,
    "declaration": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "lib": ["esnext"],
    "skipLibCheck": true,
    "allowSyntheticDefaultImports": true,
    "baseUrl": "src",
    "noImplicitAny": true,
    "typeRoots": ["./typings", "./node_modules/@types"],
    "experimentalDecorators": true
  },
  "exclude": ["node_modules", "dist"]
}

webpack.config.js:

module.exports = {
  entry: ['./src/index.ts'],
  target: 'node',
  mode: process.env.NODE_ENV === 'dev' ? 'development' : 'production',
  externals: [nodeExternals()], // in order to ignore all modules in node_modules folder,
  devtool: 'inline-source-map',
  module: {
    rules: [
      {
        test: /.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
    modules: [path.resolve(__dirname, 'src'), 'node_modules']
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'index.js'
  }
}

package.json (relevant parts):

"scripts": {
    "start-coverage": "NODE_ENV=test nyc node --reporter=lcov dist/index.js",
    ...
}, 
"nyc": {
  "all": true,
  "require": "ts-node/register",
  "instrument": true,
  "report-dir": "./coverage",
  "temp-dir": "./temp",
  "source-map": true,
  "produce-source-map": false
},

The issue is again with the stacktraces shown above unable to map individual files. I tried many combinations of configs and always end up here.

  • Anyone know what could be wrong?
  • Should I be using remap-istanbul for this?

Solution

  • Found the issue. This is a bug with webpack that was fixed in https://github.com/SitePen/remap-istanbul/issues/68.

    The solution is in webpack, you need to add option: devtoolModuleFilenameTemplate. The output section looks like this:

    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'index.js',
        devtoolModuleFilenameTemplate: '[resource-path]'}
    

    with just devtool: 'source-map' in webpack.config.js, and that was it! We didn't even need the nyc config in package.json, nor any modifications in tsconfig.json except sourceMaps:true.