我已经放弃了我的angular-cli项目,无法获得任何代码覆盖率。我尝试了各种包和配置,似乎找不到合适的组合。当我运行npm run test
测试时,DO会成功运行并显示Chrome浏览器输出。我只是希望能够设置阈值并将覆盖范围输出。
这是我的package.json
{
"name": "spa-stay-mgmt",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"lint": "ng lint",
"pree2e": "webdriver-manager update --standalone false --gecko false --quiet",
"build": "webpack",
"start": "mvn clean spring-boot:run",
"test": "karma start ./karma.conf.js --code-coverage",
"e2e": "protractor ./protractor.conf.js",
"watch": "webpack --watch --progress"
},
"private": true,
"dependencies": {
"@angular/animations": "^4.4.6",
"@angular/common": "^4.4.6",
"@angular/compiler": "^4.4.6",
"@angular/core": "^4.4.6",
"@angular/forms": "^4.4.6",
"@angular/http": "^4.4.6",
"@angular/platform-browser": "^4.4.6",
"@angular/platform-browser-dynamic": "^4.4.6",
"@angular/router": "^4.4.6",
"angular2-uuid": "^1.1.1",
"core-js": "^2.4.1",
"enquire.js": "^2.1.6",
"ng2-device-detector": "^1.0.0",
"ng2-redux": "^5.1.2",
"ng2-simple-timer": "^1.3.3",
"ngx-cookie-service": "^1.0.9",
"redux": "^3.7.2",
"redux-devtools-extension": "^2.13.2",
"redux-ui-router": "^0.7.2",
"rxjs": "^5.1.0",
"urijs": "^1.18.12",
"zone.js": "^0.8.14"
},
"devDependencies": {
"@angular/cli": "1.2.0",
"@angular/compiler-cli": "^4.0.0",
"@angular/language-service": "^4.0.0",
"@types/jasmine": "~2.5.53",
"@types/jasminewd2": "~2.0.2",
"@types/node": "~6.0.60",
"angular-in-memory-web-api": "^0.3.2",
"autoprefixer": "^6.5.3",
"clean-webpack-plugin": "^0.1.16",
"codelyzer": "~3.0.1",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "^0.28.1",
"cssnano": "^3.10.0",
"exports-loader": "^0.6.3",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^0.10.0",
"istanbul-instrumenter-loader": "^2.0.0",
"jasmine-core": "~2.6.2",
"jasmine-node": "^1.14.5",
"jasmine-spec-reporter": "~4.1.0",
"json-loader": "^0.5.4",
"karma": "~1.7.0",
"karma-chrome-launcher": "~2.1.1",
"karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"karma-phantomjs-launcher": "^1.0.4",
"less-loader": "^4.0.2",
"node-sass": "^4.5.3",
"phantomjs-prebuilt": "^2.1.14",
"postcss-loader": "^1.3.3",
"postcss-rtl": "^0.5.10",
"postcss-url": "^5.1.2",
"protractor": "~5.1.2",
"raw-loader": "^0.5.1",
"sass-lint": "^1.10.2",
"sass-loader": "^6.0.3",
"script-loader": "^0.7.0",
"source-map-loader": "^0.2.0",
"style-loader": "^0.13.1",
"stylus-loader": "^3.0.1",
"ts-node": "~3.0.4",
"tslint": "~5.3.2",
"typescript": "~2.3.3",
"url-loader": "^0.5.7",
"webpack": "^3.4.1",
"webpack-dev-server": "^2.6.1"
},
"browserslist": [
"> 1%",
"last 2 versions"
]
}
这是我的karma.conf.js
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
client:{
clearContext: false, // leave Jasmine Spec Runner output visible in browser
captureConsole: true
},
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true,
dir: '%browser%',
// enforce percentage thresholds
// anything under these percentages will cause karma to fail with an exit code of 1 if not running in watch mode
thresholds: {
emitWarning: false, // set to `true` to not fail the test command when thresholds are not met
global: { // thresholds for all files
statements: 100,
lines: 100,
branches: 100,
functions: 100
},
each: { // thresholds per file
statements: 100,
lines: 100,
branches: 100,
functions: 100
}
}
},
angularCli: {
environment: 'dev'
},
reporters: ['progress', 'kjhtml', 'coverage-istanbul'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
concurrency: Infinity,
files:[
{ pattern: 'src/main/webapp/stay-mgmt/app/**/*.spec.ts', watched: false }
]
});
};
这是我的webpack.config.js
const fs = require('fs');
const path = require('path');
const ProgressPlugin = require('webpack/lib/ProgressPlugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const autoprefixer = require('autoprefixer');
const postcssUrl = require('postcss-url');
const cssnano = require('cssnano');
const rtl = require('postcss-rtl');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { NoEmitOnErrorsPlugin, SourceMapDevToolPlugin, NamedModulesPlugin } = require('webpack');
const { GlobCopyWebpackPlugin, BaseHrefWebpackPlugin } = require('@angular/cli/plugins/webpack');
const { CommonsChunkPlugin } = require('webpack').optimize;
const { AotPlugin } = require('@ngtools/webpack');
const nodeModules = path.join(process.cwd(), 'node_modules');
const realNodeModules = fs.realpathSync(nodeModules);
const genDirNodeModules = path.join(process.cwd(), 'src/main/webapp/stay-mgmt', '$$_gendir', 'node_modules');
const entryPoints = ["inline","polyfills","sw-register","styles","vendor","main"];
const minimizeCss = true;
const baseHref = "";
const deployUrl = "";
const postcssPlugins = function () {
// safe settings based on: https://github.com/ben-eb/cssnano/issues/358#issuecomment-283696193
const importantCommentRe = /@preserve|@license|[@#]\s*source(?:Mapping)?URL|^!/i;
const minimizeOptions = {
autoprefixer: true,
safe: true,
mergeLonghand: false,
discardComments: { remove: (comment) => !importantCommentRe.test(comment) }
};
return [
postcssUrl({
url: (URL) => {
// Only convert root relative URLs, which CSS-Loader won't process into require().
if (!URL.startsWith('/') || URL.startsWith('//')) {
return URL;
}
if (deployUrl.match(/:\/\//)) {
// If deployUrl contains a scheme, ignore baseHref use deployUrl as is.
return `${deployUrl.replace(/\/$/, '')}${URL}`;
}
else if (baseHref.match(/:\/\//)) {
// If baseHref contains a scheme, include it as is.
return baseHref.replace(/\/$/, '') +
`/${deployUrl}/${URL}`.replace(/\/\/+/g, '/');
}
else {
// Join together base-href, deploy-url and the original URL.
// Also dedupe multiple slashes into single ones.
return `/${baseHref}/${deployUrl}/${URL}`.replace(/\/\/+/g, '/');
}
}
}),
//rtl(),
autoprefixer(),
].concat(minimizeCss ? [cssnano(minimizeOptions)] : []);
};
module.exports = {
"resolve": {
"extensions": [
".ts",
".js"
],
"modules": [
"./node_modules",
"./node_modules"
],
"symlinks": true
},
"resolveLoader": {
"modules": [
"./node_modules",
"./node_modules"
]
},
"entry": {
"main": [
"./src/main/webapp/stay-mgmt/main.ts"
],
"polyfills": [
"./src/main/webapp/stay-mgmt/polyfills.ts"
],
"styles": [
"./src/main/webapp/stay-mgmt/style/styles.scss"
]
},
"output": {
"path": path.join(process.cwd(), "./src/main/webapp/stay-mgmt/dist"),
"filename": "[name].bundle.js",
"chunkFilename": "[id].chunk.js"
},
"module": {
"rules": [
{
"enforce": "pre",
"test": /\.js$/,
"loader": "source-map-loader",
"exclude": [
/\/node_modules\//
]
},
{
"test": /\.json$/,
"loader": "json-loader"
},
{
"test": /\.html$/,
"loader": "raw-loader"
},
{
"test": /\.(eot|svg)$/,
"loader": "file-loader?name=[name].[hash:20].[ext]"
},
{
"test": /\.(jpg|png|webp|gif|otf|ttf|woff|woff2|cur|ani)$/,
"loader": "url-loader?name=[name].[hash:20].[ext]&limit=10000"
},
{
"exclude": [
path.join(process.cwd(), "src/main/webapp/stay-mgmt/style/styles.scss")
],
"test": /\.css$/,
"use": [
"exports-loader?module.exports.toString()",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
}
]
},
{
"exclude": [
path.join(process.cwd(), "src/main/webapp/stay-mgmt/style/styles.scss")
],
"test": /\.scss$|\.sass$/,
"use": [
"exports-loader?module.exports.toString()",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "sass-loader",
"options": {
"sourceMap": false,
"precision": 8,
"includePaths": []
}
}
]
},
{
"exclude": [
path.join(process.cwd(), "src/main/webapp/stay-mgmt/style/styles.scss")
],
"test": /\.less$/,
"use": [
"exports-loader?module.exports.toString()",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "less-loader",
"options": {
"sourceMap": false
}
}
]
},
{
"exclude": [
path.join(process.cwd(), "src/main/webapp/stay-mgmt/style/styles.scss")
],
"test": /\.styl$/,
"use": [
"exports-loader?module.exports.toString()",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "stylus-loader",
"options": {
"sourceMap": false,
"paths": []
}
}
]
},
{
"include": [
path.join(process.cwd(), "src/main/webapp/stay-mgmt/style/styles.scss")
],
"test": /\.css$/,
"use": [
"style-loader",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
}
]
},
{
"include": [
path.join(process.cwd(), "src/main/webapp/stay-mgmt/style/styles.scss")
],
"test": /\.scss$|\.sass$/,
"use": [
"style-loader",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "sass-loader",
"options": {
"sourceMap": false,
"precision": 8,
"includePaths": []
}
}
]
},
{
"include": [
path.join(process.cwd(), "src/main/webapp/stay-mgmt/style/styles.scss")
],
"test": /\.less$/,
"use": [
"style-loader",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "less-loader",
"options": {
"sourceMap": false
}
}
]
},
{
"include": [
path.join(process.cwd(), "src/main/webapp/stay-mgmt/style/styles.scss")
],
"test": /\.styl$/,
"use": [
"style-loader",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "stylus-loader",
"options": {
"sourceMap": false,
"paths": []
}
}
]
},
{
"test": /\.ts$/,
"loader": "@ngtools/webpack"
}
]
},
"plugins": [
new CleanWebpackPlugin(['src/main/webapp/stay-mgmt/dist']),
new CopyWebpackPlugin([
{ from: "src/main/resources/adrum/", to: "adrum/" },
{ from: "src/main/resources/translations/", to: 'translations/' }
]),
new NoEmitOnErrorsPlugin(),
new GlobCopyWebpackPlugin({
"patterns": [
"assets",
"favicon.ico"
],
"globOptions": {
"cwd": path.join(process.cwd(), "src/main/webapp/stay-mgmt"),
"dot": true,
"ignore": "**/.gitkeep"
}
}),
new ProgressPlugin(),
new SourceMapDevToolPlugin({
"filename": "[file].map[query]",
"moduleFilenameTemplate": "[resource-path]",
"fallbackModuleFilenameTemplate": "[resource-path]?[hash]",
"sourceRoot": "webpack:///"
}),
new HtmlWebpackPlugin({
"template": "src/main/webapp/stay-mgmt/index.html",
"filename": "./index.html",
"hash": false,
"inject": true,
"compile": true,
"favicon": false,
"minify": false,
"cache": true,
"showErrors": true,
"chunks": "all",
"excludeChunks": [],
"title": "Webpack App",
"xhtml": true,
"chunksSortMode": function sort(left, right) {
let leftIndex = entryPoints.indexOf(left.names[0]);
let rightindex = entryPoints.indexOf(right.names[0]);
if (leftIndex > rightindex) {
return 1;
}
else if (leftIndex < rightindex) {
return -1;
}
else {
return 0;
}
}
}),
new BaseHrefWebpackPlugin({}),
new CommonsChunkPlugin({
"minChunks": 2,
"async": "common"
}),
new CommonsChunkPlugin({
"name": [
"inline"
],
"minChunks": null
}),
new CommonsChunkPlugin({
"name": [
"vendor"
],
"minChunks": (module) => {
return module.resource
&& (module.resource.startsWith(nodeModules)
|| module.resource.startsWith(genDirNodeModules)
|| module.resource.startsWith(realNodeModules));
},
"chunks": [
"main"
]
}),
new NamedModulesPlugin({}),
new AotPlugin({
"mainPath": "main.ts",
"hostReplacementPaths": {
"environments/environment.ts": "environments/environment.ts"
},
"exclude": [],
"tsConfigPath": "src/main/webapp/stay-mgmt/tsconfig.app.json",
"skipCodeGeneration": true
})
],
"node": {
"fs": "empty",
"global": true,
"crypto": "empty",
"tls": "empty",
"net": "empty",
"process": true,
"module": false,
"clearImmediate": false,
"setImmediate": false
},
"devServer": {
"historyApiFallback": true
}
};
答案 0 :(得分:1)
我在弹出的CLI应用程序中将以下内容添加到 karma.conf.js 文件中,以使覆盖率正常工作。
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly', 'text-summary' ],
fixWebpackSourcePaths: true
},
angularCli: {
environment: 'dev',
codeCoverage: true
},
reporters: config.angularCli && config.angularCli.codeCoverage
? ['progress', 'coverage-istanbul']
: ['progress', 'kjhtml'],
与原始版本的唯一区别是在覆盖率报告中添加了text-summary
,在codeCoverage: true
下添加了angularCli
,以及reporters
逻辑。
现在,当我运行npm run test
时,我会得到如下文字摘要,以及项目文件夹根目录 coverage 文件夹中的HTML报告。
=============================== Coverage summary ===============================
Statements : 100% ( 28/28 )
Branches : 100% ( 0/0 )
Functions : 100% ( 6/6 )
Lines : 100% ( 24/24 )
================================================================================
如果要关闭覆盖范围,请在 karma.conf.js 中将codeCoverage
设置为false。
这是我发现能够在弹出 CLI应用程序中使用覆盖率报告的唯一方法。
我刚刚使用CLI版本1.5.4在新推出的应用程序上对此进行了测试,但它确实有效。
答案 1 :(得分:0)
代码覆盖率采用一个参数,默认情况下为false。在你的情况下,你传递--code-coverage
但没有传递任何值,所以它默认采用false
。
试试这个
ng test -c karma.conf.js --code-coverage true --single-run true
您也可以将它添加到package.json中,并从命令
中调用它“test”:“ng test --code-coverage true”
然后npm run test