Angular-CLI代码覆盖率问题

时间:2017-11-24 16:34:13

标签: angular angular-cli code-coverage karma-webpack webpack-3

我已经放弃了我的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
  }
};

2 个答案:

答案 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