Istanbul Coverage 不适用于 Karma、Mocha、Webpack
Istanbul Coverage does not work with Karma, Mocha, Webpack
我按照代码设置了 webpack 和 karama 配置。
webpack.config.js
/* global module, process, require, __dirname */
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const fs = require('fs');
const gc = require('./global.config.js');
// extract style
const extractCss = new ExtractTextPlugin({
filename: 'css/[name].css'
});
const extractSass = new ExtractTextPlugin({
filename: 'css/[name].css'
});
// dir path
const sourceDir = gc.basePath+ gc.baseDir + gc.resourceDir;
const outputDir = gc.baseDir + gc.resourceDir + gc.distDir;
const devPort = 9090;
const devOutputDir = gc.resourceDir + gc.distDir;
// generate entry
const fileDir = sourceDir + '/js';
const read = (dir) =>
fs.readdirSync(dir)
.reduce((files, file) => {
const filePath = dir + '/' +file;
if (fs.statSync(filePath).isDirectory()) {
return files.concat(read(filePath));
}
if (file !== 'entry.js') {
return files;
}
return files.concat(filePath);
}, []);
const getEntry = (files) => {
const entry = {};
files.forEach(file => {
const key = file.replace(fileDir + '/', '').replace('.js', '');
entry[key] = ['babel-polyfill', file];
});
return entry;
};
const entry = getEntry(read(fileDir));
// webpack config
const config = {
entry: Object.assign({}, gc.vendors.entry, entry),
output: {
path: __dirname + outputDir,
filename: 'js/[name].bundle.js',
publicPath: '/',
libraryTarget: 'umd', // export itself to a global var
library: 'sc' // name of the global var: 'sc'
},
resolve: {
modules: ['node_modules'],
extensions: ['.js', '.jsx', '.css', '.scss']
},
devtool: 'source-map',
cache: true,
plugins: [
extractCss,
extractSass,
new webpack.ProvidePlugin(gc.vendors.providePlugin)
],
devServer: {
host: '0.0.0.0',
publicPath: 'http://localhost:' + devPort + '/',
port: devPort,
disableHostCheck: true,
noInfo: true,
inline: true,
proxy: {
'**': 'http://localhost:8080'
}
},
module: {
rules: [{
enforce: 'pre',
test: /\.(js|jsx)?$/,
loader: 'eslint-loader',
exclude: /(node_modules|bower_components)/
}, {
test: /\.(js|jsx)?$/,
loader: 'babel-loader',
exclude: /(node_modules|bower_components)/,
query: {
cacheDirectory: true,
presets: ['es2015', 'react']
}
}, {
test: /\.css$/,
use: extractCss.extract({
fallback: 'style-loader',
use: 'css-loader'
})
}, {
test: /\.scss$/,
use: extractSass.extract({
use: [{
loader: 'css-loader', options: {
sourceMap: true
}
}, {
loader: 'sass-loader', options: {
sourceMap: true
}
}],
// use style-loader in development
fallback: 'style-loader'
})
}]
}
};
const env = process.env.NODE_ENV;
// develop phase
if (env === 'development') {
config.output.publicPath = 'http://localhost:' + devPort + devOutputDir;
}
// production phase
if (env === 'production') {
config.devtool = '#source-map';
config.plugins = (config.plugins || []).concat([
new webpack.optimize.CommonsChunkPlugin({
name: 'vendors'
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
module.exports = config;
karma.config.js
/* global module, require */
const path = require('path');
const webpackConfig = require('./webpack.config.js');
const gc = require('./global.config.js');
// dir path
const sourceDir = gc.baseDir + gc.resourceDir;
const sourcePattern = gc.basePath + gc.baseDir + gc.resourceDir + '/js/**/*.js';
const testPattern = gc.basePath + gc.baseDir + gc.testDir + '/**/*.spec.js';
const preprocessor = {};
preprocessor[sourcePattern] = ['webpack', 'coverage'];
preprocessor[testPattern] = ['webpack'];
// add webpack test config
const rules = [{
test: /sinon.*\.js$/,
loader: "imports-loader?define=>false,require=>false"
}, {
enforce: 'post',
test: /\.js/,
exclude: /(node_modules|bower_components)/,
include: path.join(sourceDir), // instrument only testing sources with Istanbul, after ts-loader runs
loader: 'istanbul-instrumenter-loader'
}];
webpackConfig.module.rules = webpackConfig.module.rules.concat(rules);
webpackConfig.module['noParse'] = [/sinon/];
webpackConfig.resolve['alias'] = {sinon: 'sinon/pkg/sinon'};
module.exports = function (config) {
config.set({
frameworks: [
'mocha',
'chai',
'sinon'
],
files: [
{pattern: sourcePattern, watched: false},
{pattern: testPattern, watched: false}
],
browsers: ['Chrome', 'Firefox'],
preprocessors: preprocessor,
// report
reporters: ['mocha', 'coverage'],
coverageReporter: {
dir: path.join(__dirname, 'coverage'),
reporters: [
{
type: 'html',
subdir: 'report-html'
},
{
type: 'lcov',
subdir: 'report-lcov'
},
{
type: 'cobertura',
subdir: '.',
file: 'cobertura.txt'
},
{
type: 'text',
subdir: '.',
file: 'report-text.txt'
},
{
type: 'text-summary'
}
],
fixWebpackSourcePaths: true
},
// client
client: {
mocha: {
// change Karma's debug.html to the mocha web reporter
reporter: 'html',
// require specific files after Mocha is initialized
require: [require.resolve('bdd-lazy-var/bdd_lazy_var_global')],
// custom ui, defined in required file above
ui: 'bdd-lazy-var/global',
}
},
// webpack
webpack: webpackConfig,
webpackMiddleware: {
stats: 'errors-only'
},
});
};
但它没有像我预期的那样工作。它都是用 babel 转译的,所以它的覆盖范围是错误的。它检查了包含的库,例如 jQuery.
[INFO] =============================== Coverage summary ===============================
[INFO] Statements : 19.59% ( 704/3593 )
[INFO] Branches : 6.11% ( 208/3402 )
[INFO] Functions : 17.32% ( 111/641 )
[INFO] Lines : 19.59% ( 703/3588 )
[INFO] ================================================================================
我的配置有什么问题?这是我的全部代码。 https://github.com/egaoneko/maven-spring-webpack-scaffold
伊斯坦布尔对 ES6 不是很好。创建一个构建文件夹,将翻译后的 ES6 或 JSX 代码以普通 JS 放入伊斯坦布尔可以理解的构建中。这是我开始使用 Istanbul 进行代码覆盖时了解到的缺点之一。此外,用 vanilla JavaScript 编写你的测试,这样伊斯坦布尔就能理解你的测试。我在 ES6 中编写我的函数并在 vanilla Javascript 中使用 mocha 和 chai 进行测试。
因为我在我的 package.json
中使用 npm run
进行测试,所以我有我的测试
nyc --reporter=html --reporter=text mocha test/**/*.test.js
这行得通吗?
我按照代码设置了 webpack 和 karama 配置。
webpack.config.js
/* global module, process, require, __dirname */
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const fs = require('fs');
const gc = require('./global.config.js');
// extract style
const extractCss = new ExtractTextPlugin({
filename: 'css/[name].css'
});
const extractSass = new ExtractTextPlugin({
filename: 'css/[name].css'
});
// dir path
const sourceDir = gc.basePath+ gc.baseDir + gc.resourceDir;
const outputDir = gc.baseDir + gc.resourceDir + gc.distDir;
const devPort = 9090;
const devOutputDir = gc.resourceDir + gc.distDir;
// generate entry
const fileDir = sourceDir + '/js';
const read = (dir) =>
fs.readdirSync(dir)
.reduce((files, file) => {
const filePath = dir + '/' +file;
if (fs.statSync(filePath).isDirectory()) {
return files.concat(read(filePath));
}
if (file !== 'entry.js') {
return files;
}
return files.concat(filePath);
}, []);
const getEntry = (files) => {
const entry = {};
files.forEach(file => {
const key = file.replace(fileDir + '/', '').replace('.js', '');
entry[key] = ['babel-polyfill', file];
});
return entry;
};
const entry = getEntry(read(fileDir));
// webpack config
const config = {
entry: Object.assign({}, gc.vendors.entry, entry),
output: {
path: __dirname + outputDir,
filename: 'js/[name].bundle.js',
publicPath: '/',
libraryTarget: 'umd', // export itself to a global var
library: 'sc' // name of the global var: 'sc'
},
resolve: {
modules: ['node_modules'],
extensions: ['.js', '.jsx', '.css', '.scss']
},
devtool: 'source-map',
cache: true,
plugins: [
extractCss,
extractSass,
new webpack.ProvidePlugin(gc.vendors.providePlugin)
],
devServer: {
host: '0.0.0.0',
publicPath: 'http://localhost:' + devPort + '/',
port: devPort,
disableHostCheck: true,
noInfo: true,
inline: true,
proxy: {
'**': 'http://localhost:8080'
}
},
module: {
rules: [{
enforce: 'pre',
test: /\.(js|jsx)?$/,
loader: 'eslint-loader',
exclude: /(node_modules|bower_components)/
}, {
test: /\.(js|jsx)?$/,
loader: 'babel-loader',
exclude: /(node_modules|bower_components)/,
query: {
cacheDirectory: true,
presets: ['es2015', 'react']
}
}, {
test: /\.css$/,
use: extractCss.extract({
fallback: 'style-loader',
use: 'css-loader'
})
}, {
test: /\.scss$/,
use: extractSass.extract({
use: [{
loader: 'css-loader', options: {
sourceMap: true
}
}, {
loader: 'sass-loader', options: {
sourceMap: true
}
}],
// use style-loader in development
fallback: 'style-loader'
})
}]
}
};
const env = process.env.NODE_ENV;
// develop phase
if (env === 'development') {
config.output.publicPath = 'http://localhost:' + devPort + devOutputDir;
}
// production phase
if (env === 'production') {
config.devtool = '#source-map';
config.plugins = (config.plugins || []).concat([
new webpack.optimize.CommonsChunkPlugin({
name: 'vendors'
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
module.exports = config;
karma.config.js
/* global module, require */
const path = require('path');
const webpackConfig = require('./webpack.config.js');
const gc = require('./global.config.js');
// dir path
const sourceDir = gc.baseDir + gc.resourceDir;
const sourcePattern = gc.basePath + gc.baseDir + gc.resourceDir + '/js/**/*.js';
const testPattern = gc.basePath + gc.baseDir + gc.testDir + '/**/*.spec.js';
const preprocessor = {};
preprocessor[sourcePattern] = ['webpack', 'coverage'];
preprocessor[testPattern] = ['webpack'];
// add webpack test config
const rules = [{
test: /sinon.*\.js$/,
loader: "imports-loader?define=>false,require=>false"
}, {
enforce: 'post',
test: /\.js/,
exclude: /(node_modules|bower_components)/,
include: path.join(sourceDir), // instrument only testing sources with Istanbul, after ts-loader runs
loader: 'istanbul-instrumenter-loader'
}];
webpackConfig.module.rules = webpackConfig.module.rules.concat(rules);
webpackConfig.module['noParse'] = [/sinon/];
webpackConfig.resolve['alias'] = {sinon: 'sinon/pkg/sinon'};
module.exports = function (config) {
config.set({
frameworks: [
'mocha',
'chai',
'sinon'
],
files: [
{pattern: sourcePattern, watched: false},
{pattern: testPattern, watched: false}
],
browsers: ['Chrome', 'Firefox'],
preprocessors: preprocessor,
// report
reporters: ['mocha', 'coverage'],
coverageReporter: {
dir: path.join(__dirname, 'coverage'),
reporters: [
{
type: 'html',
subdir: 'report-html'
},
{
type: 'lcov',
subdir: 'report-lcov'
},
{
type: 'cobertura',
subdir: '.',
file: 'cobertura.txt'
},
{
type: 'text',
subdir: '.',
file: 'report-text.txt'
},
{
type: 'text-summary'
}
],
fixWebpackSourcePaths: true
},
// client
client: {
mocha: {
// change Karma's debug.html to the mocha web reporter
reporter: 'html',
// require specific files after Mocha is initialized
require: [require.resolve('bdd-lazy-var/bdd_lazy_var_global')],
// custom ui, defined in required file above
ui: 'bdd-lazy-var/global',
}
},
// webpack
webpack: webpackConfig,
webpackMiddleware: {
stats: 'errors-only'
},
});
};
但它没有像我预期的那样工作。它都是用 babel 转译的,所以它的覆盖范围是错误的。它检查了包含的库,例如 jQuery.
[INFO] =============================== Coverage summary ===============================
[INFO] Statements : 19.59% ( 704/3593 )
[INFO] Branches : 6.11% ( 208/3402 )
[INFO] Functions : 17.32% ( 111/641 )
[INFO] Lines : 19.59% ( 703/3588 )
[INFO] ================================================================================
我的配置有什么问题?这是我的全部代码。 https://github.com/egaoneko/maven-spring-webpack-scaffold
伊斯坦布尔对 ES6 不是很好。创建一个构建文件夹,将翻译后的 ES6 或 JSX 代码以普通 JS 放入伊斯坦布尔可以理解的构建中。这是我开始使用 Istanbul 进行代码覆盖时了解到的缺点之一。此外,用 vanilla JavaScript 编写你的测试,这样伊斯坦布尔就能理解你的测试。我在 ES6 中编写我的函数并在 vanilla Javascript 中使用 mocha 和 chai 进行测试。
因为我在我的 package.json
中使用 npm run
进行测试,所以我有我的测试
nyc --reporter=html --reporter=text mocha test/**/*.test.js
这行得通吗?