bySabi/karma-istanbuljs-reporter

[feature request] add `include all sources` feature

Opened this issue · 11 comments

karma-istanbuljs-reporter don't instrument files. Instrumentation relay on babel-istanbul-plugin, trying to implement include all sources must be done upstream at babel-loader or babel plugin level
I start this issue looking for help about the subject.

@ColCh maybe can you help here with some advice? I though this can be done with webpack require.context or webpack plugin. Something like require all files on a dir

ColCh commented

yes, it's pretty easy to achieve. Create all-tests.js with content of require.context[1], then import it in karma

I don't have actual code snippet for this, because I deleted it - running tests is very slow with this method.

[1] docs: https://webpack.github.io/docs/context.html#require-context

Thanks a ton @ColCh, I goto test it.

One last thing about webpack ...

I was trying to replace:

const context = require.context('./test', true, /^.+\.(js|jsx)+$/g);
context.keys().forEach(context);

with

var RequireContextPlugin = require('webpack/lib/dependencies/RequireContextPlugin');
...
  plugins: [
    //new RequireContextPlugin(['./test'], [/^.+\.(js|jsx)+$/g])
    new RequireContextPlugin(['./test'], ['.js'])
 ]

Is this suitable?

ColCh commented

is this public api? I didn't knew anything about RequireContextPlugin...

Is a internal plugin: https://github.com/webpack/docs/wiki/internal-webpack-plugins#dependenciesrequirecontextpluginmodulesdirectories-extensions

From this issue: webpack/webpack#1208 it seems that require.context is implemented on top of it.

What I wanna do is set require files from webpack.config.js using a Webpack internal plugin or 3rd party and not using a external source file like all-tests.js.
I was looking at: https://github.com/andreypopp/prefetch-context-webpack-plugin but without look.

I really don´t have too much knowledge on webpack and I mentally exaust at this point from too much hours looking at Istanbul source code. Any help on this subject is really welcome.

ColCh commented

this is my karma configuration file, I've used it to test ES6/JSX source, using karma as test tool, and webpack to handle modules.

It's a big snippet, I just can't cut down unneded chunks, because I don't really remember, what here is important, and what's not.

var webpack = require('webpack');
var path = require('path');
var RewirePlugin = require("rewire-webpack");

module.exports = function (config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['mocha', 'sinon-chai'],

    // list of files / patterns to load in the browser
    files: [
      'specs/**/*.jsx'
    ],

    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
      'specs/**/*.jsx': ["webpack"]
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    reporters: ['mocha'],

    coverageReporter: {
        type : 'html',
        dir : 'coverage/'
    },

    // web server port
    port: 9876,

    // Timeout for capturing a browser (in ms).
    captureTimeout: 60 * 1e3,

    // to avoid DISCONNECTED messages
    browserDisconnectTimeout : 10000, // default 2000
    browserDisconnectTolerance : 1, // default 0
    browserNoActivityTimeout : 60 * 1e3, //default 10000

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_ERROR,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['PhantomJS'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Include timeout because of rsync
    autoWatchBatchDelay: 2 * 1e3,

    // webpack options
    webpack: {
      cache: true,
      devtool: false,
      watchDelay: 3 * 1e3,
      resolve: {
        extensions: ['', ".webpack.js", '.js', '.jsx'],
        modulesDirectories: ["node_modules", "bower_components"],
        alias: {
          'flux': path.join(__dirname, 'src/scripts/flux'),
          'src': path.join(__dirname, 'src/'),
          'routes': path.join(__dirname, 'src/scripts/routes'),
          'components': path.join(__dirname, 'src/scripts/components'),
          'scripts': path.join(__dirname, 'src/scripts'),
          'styles': path.join(__dirname, 'src/styles')
        }
      },
      module: {
        preLoaders: [
            {test: /(\.jsx)|(\.js)$/, exclude: /(node_modules|bower_components|specs|ckeditor)/, loader: 'isparta-instrumenter'},
            {test: /src\/.+(\.jsx)|(\.js)$/, exclude: /node_modules/, loader: 'imports?globals=scripts/globals.js'}
        ],
        loaders: [
          {test: /(react)|(react\/addons)$/, loader: 'expose?React!imports?shim=es5-shim/es5-shim&sham=es5-shim/es5-sham'},
          {test: /\/jquery.js$/, loader: 'expose?jQuery'},
          {test: /react-tabs.*\.js$/, loader: 'babel-loader?experimental&optional=selfContained'},
          {test: /(\.jsx)|(\.js)$/, exclude: /node_modules/, loader: 'babel-loader?experimental&optional=selfContained'},
          {test: /\.css$/, loader:  'null'},
          {test: /\.(png|jpg|gif)$/, loader: 'null'},
          {test: /icon-.+\.(svg)$/, loader: 'null'},
          {test: /\.styl$/, loader: 'null'},
          {test: /\.woff.?$/, loader: "null" },
          {test: /fonts\/.*\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "null"},
          {test: /\.json$/, loader: "json-loader"},
          {test: /bootstrap\/js\//, loader: 'imports?jQuery=jquery'}
        ]
      },
      plugins: [
        new RewirePlugin(),
        new webpack.PrefetchPlugin('react'),
        new webpack.PrefetchPlugin('jquery'),
        new webpack.PrefetchPlugin('lodash'),
        new webpack.PrefetchPlugin('fluxxor'),
        new webpack.PrefetchPlugin('react-router'),
        new webpack.ProvidePlugin({
          React: 'react/addons',
          _: 'lodash',
          Router: 'react-router',
          Fluxxor: 'fluxxor',
          '$': 'jquery',
        }),
        new webpack.DefinePlugin({'global.BACKEND_HOST': '"http://localhost:8080/"'}),
        new webpack.DefinePlugin({'global.RESOURCE_PATH_PREFIX': '"http://localhost:8000"'}),
        new webpack.DefinePlugin({'process.env.NODE_ENV': '"development"', 'global.SIDE': '"frontend"'}),
        new webpack.DefinePlugin({'process.env.BLUEBIRD_DEBUG': '1', '__DEV__': 'true'}),
        new webpack.ResolverPlugin(
          new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
        )
      ],
      devServer: {
        contentBase: './src/',
      },
    },

    webpackMiddleware: {
      stats: {
        // With console colors
        colors: true,
        // add the hash of the compilation
        hash: false,
        // add webpack version information
        version: false,
        // add timing information
        timings: true,
        // add assets information
        assets: false,
        // add chunk information
        chunks: false,
        // add built modules information to chunk information
        chunkModules: false,
        // add built modules information
        modules: false,
        // add also information about cached (not built) modules
        cached: false,
        // add information about the reasons why modules are included
        reasons: false,
        // add the source code of modules
        source: true,
        // add details to errors (like resolving log)
        errorDetails: true,
        // add the origins of chunks and chunk merging info
        chunkOrigins: true,
        // Add messages from child loaders
        children: false
      }
    },

  });
};

I was using isparta-instrumenter to do instumenting magic (derecated as 2016 by other module).

And I've used no require.context, tests from specs (specs/FooBar.jsx...) were loaded and tested one-by-one, not in a big-bundle

I think, that using preLoaders can point you the right way of instumenting code using karma&webpack.

I'm sorry, but I don't use Karma, and don't do any WEB development about one year, many things of FrontEnd go out of mind...

Good luck with tooling! This is a really hard thing.

Good!! thanks for shared your code.
I will investigate preLoaders path.

Maybe a webpack guy can make a bit of input here ...

@bebraw, any advice ??

@bySabi If I remember right, you can instrument through Babel. There is some plugin for that. I also have a working Karma setup here if you want to have a look. I've moved to Jest myself (easy transition) as the setup is so simple and coverage just works.

@bebraw, I still on karma cause for some React Components I need a "real" browser environment, say Chrome or Firefox and this is not possible with Jest.
Some times ago I could not use Jest and enzyme together, this seems solved in some rc or beta.
And cause I´m a TAP guy more than Jasmine :-)

I use a Babel plugin for Instrumentation, babel-plugin-istanbul, but for add a feature like include all sources who basically instrument files that are not been require some work must be done at webpack/babel-loader level.
It seems that I can add all require and not require files following classic tests.webpack.js aproach use on many karma/webpack settings for bundle all test on one file.

tests.webpack.js

const context = require.context('./test', true, /^.+\.(js|jsx)+$/g);
context.keys().forEach(context);

But for instrument all sources is just ...

all-sources.js

const context = require.context('./src', true, /^.+\.(js|jsx)+$/g);
context.keys().forEach(context);

But I need to parameterize src folder and extension regex. I really do this on another project: https://github.com/bySabi/carma-tap-webpack/blob/master/tests.webpack.js with globals and DefinePlugin

...
plugins: [
        new webpack.DefinePlugin({
          '__TEST_DIR__': JSON.stringify('../../test'),
          '__TEST_REGX__': /^.+\.(js|jsx)+$/g
        })
],
...

What I really wanna do is avoid require.context file setup but require files from webpack.conf.js using plugins like webpack RequireContextPlugin or something like https://github.com/andreypopp/prefetch-context-webpack-plugin
But I don´t kow is this suitable on someway.
A webpack expert is need here :-)

I take a look at your karma.conf.js but I could not found an answer.

Another direction. Point to the file handling require.context through a custom entry.

I remember Karma Istanbul has some custom options so those are worth studying too.

With entry I still need tests.webpack.js for require files.
@sokra, settings like in tests.webpack.js is the only way to require modules in context?

Still working on a solution lets invited another developer to the party.
@TheLarkInn, any input here?