向ASP.NET Core Angular 2 Starter应用程序添加代码覆盖率 [英] Adding code coverage to the ASP.NET Core Angular 2 Starter Application

查看:57
本文介绍了向ASP.NET Core Angular 2 Starter应用程序添加代码覆盖率的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在安装.NET Core 2.0 SDK之后,我已经使用Visual Studio 2017 Update 3中提供的Angular ASP.NET Core 2.0模板启动了一个项目.

I have started a project by using the Angular ASP.NET Core 2.0 template as found in Visual Studio 2017 Update 3 after installing the .NET Core 2.0 SDK.

Karma中的测试工作正常,但我想为Karma添加代码覆盖率.我尝试了几种不同的解决方案,但似乎没有什么能充分发挥作用.我想出的最好的办法是涵盖了从测试引用的类(但不是ClientApp中的所有打字稿类),但是生成的报告中的突出显示已关闭,消息没有意义.

Tests in Karma work fine, but I want to add code coverage to Karma. I have tried several different solutions, but nothing seems to work fully. The best I have come up with is that classes referenced from tests are covered (but not all typescript classes in the ClientApp), but the highlighting in the generated report is off and the messages don't make sense.

这就是我所做的:

package.json

package.json

"devDependencies": {
    "@types/chai": "4.0.1",
    "@types/jasmine": "2.5.53",
    "chai": "4.0.2",
    "istanbul-instrumenter-loader": "^3.0.0",
    "jasmine-core": "2.6.4",
    "karma": "https://registry.npmjs.org/karma/-/karma-1.7.0.tgz",
    "karma-chai": "0.1.0",
    "karma-chrome-launcher": "2.2.0",
    "karma-cli": "1.0.1",
    "karma-coverage": "^1.1.1",
    "karma-jasmine": "1.1.0",
    "karma-remap-istanbul": "https://registry.npmjs.org/karma-remap-istanbul/-/karma-remap-istanbul-0.6.0.tgz",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-webpack": "2.0.3"
  }

Karma.conf.js:

Karma.conf.js:

module.exports = function (config) {
    var webpackConfig = require('../../webpack.config.js')().filter(config => config.target !== 'node');
    webpackConfig[0].devtool = 'inline-source-map';

    config.set({
        basePath: '.',
        frameworks: ['jasmine'],
        files: [
            '../../wwwroot/dist/vendor.js',
            './boot-tests.ts'
        ],
        preprocessors: {
            './boot-tests.ts': ['webpack', 'sourcemap']
        },
        reporters: ['progress', 'coverage', 'karma-remap-istanbul'],
        port: 9876,
        colors: true,
        logLevel: config.LOG_INFO,
        autoWatch: true,
        browsers: ['Chrome'],
        mime: { 'application/javascript': ['ts','tsx'] },
        singleRun: false,
        webpack: webpackConfig, // Test against client bundle, because tests run in a browser
        webpackMiddleware: { stats: 'errors-only' },
        remapIstanbulReporter: {
            reports: {
                html: 'coverage'
            }
        }
    });
};

webpack.config.js:

webpack.config.js:

const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const AotPlugin = require('@ngtools/webpack').AotPlugin;
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;

module.exports = (env) => {
    // Configuration in common to both client-side and server-side bundles
    const isDevBuild = !(env && env.prod);

    const tsUse = isDevBuild ? [
        {
            loader: 'istanbul-instrumenter-loader',
            options: {
                esModules: true
            }
        },
        'awesome-typescript-loader?silent=true',
        'angular2-template-loader'
    ] : '@ngtools/webpack';

    const sharedConfig = {
        stats: { modules: false },
        context: __dirname,
        resolve: { extensions: ['.js', '.ts'] },
        output: {
            filename: '[name].js',
            publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
        },
        module: {
            rules: [
                {
                    test: /\.ts$/, include: /ClientApp/,
                    use: tsUse
                },
                { test: /\.html$/, use: 'html-loader?minimize=false' },
                {
                    test: /\.css$/, use: ['to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize']
                },
                { test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
            ]
        },
        plugins: [new CheckerPlugin()]
    };

    // Configuration for client-side bundle suitable for running in browsers
    const clientBundleOutputDir = './wwwroot/dist';
    const clientBundleConfig = merge(sharedConfig, {
        entry: { 'main-client': './ClientApp/boot.browser.ts' },
        output: { path: path.join(__dirname, clientBundleOutputDir) },
        plugins: [
            new webpack.DllReferencePlugin({
                context: __dirname,
                manifest: require('./wwwroot/dist/vendor-manifest.json')
            })
        ].concat(isDevBuild ? [
            // Plugins that apply in development builds only
            new webpack.SourceMapDevToolPlugin({
                filename: '[file].map', // Remove this line if you prefer inline source maps
                moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
            })
        ] : [
                // Plugins that apply in production builds only
                new webpack.optimize.UglifyJsPlugin(),
                new AotPlugin({
                    tsConfigPath: './tsconfig.json',
                    entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'),
                    exclude: ['./**/*.server.ts']
                })
            ])
    });

    // Configuration for server-side (prerendering) bundle suitable for running in Node
    const serverBundleConfig = merge(sharedConfig, {
        resolve: { mainFields: ['main'] },
        entry: { 'main-server': './ClientApp/boot.server.ts' },
        plugins: [
            new webpack.DllReferencePlugin({
                context: __dirname,
                manifest: require('./ClientApp/dist/vendor-manifest.json'),
                sourceType: 'commonjs2',
                name: './vendor'
            })
        ].concat(isDevBuild ? [] : [
            // Plugins that apply in production builds only
            new AotPlugin({
                tsConfigPath: './tsconfig.json',
                entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'),
                exclude: ['./**/*.browser.ts']
            })
        ]),
        output: {
            libraryTarget: 'commonjs',
            path: path.join(__dirname, './ClientApp/dist')
        },
        target: 'node',
        devtool: 'inline-source-map'
    });

    return [clientBundleConfig, serverBundleConfig];
};

推荐答案

我最近一直在研究这个问题,经过一番挖掘,我最终得到了下面的解决方案.

I have been working on this lately, and after some digging I ended up with the below a solution.

注意::请参阅本文底部的参考资料,以了解最终发现的解决方案.这足够(有必要)与来源有所不同,所以我认为我不应该为版权问题而烦恼.

NOTE: See the references at the bottom of this post to see what I found to eventually get to this solution. Enough of this is (necessarily) different from the source, so I don't think I should get into an trouble concerning copyrights.

首先,我将它们添加到解决方案的 package.json 中,该解决方案是使用Visual Studio 2017(15.3及更高版本中提供的新ASP.NET Core 2.0 Angular模板开始的)思考).将它们添加到 package.json devDependencies部分.

First, I added these to the package.json for my solution, which was started using the new ASP.NET Core 2.0 Angular template that is available with Visual Studio 2017 (15.3 and up, I think). Add these to the devDependencies section of the package.json.

"karma-sourcemap-loader": "^0.3.7",
"karma-remap-istanbul": "^0.6.0",
"istanbul-instrumenter-loader": "^3.0.0"

运行npm install将位添加到应用程序中,或保存 package.json 并让VS完成.

Run npm install to add the bits into the application, or save the package.json and let VS do it's thing.

接下来,我更改了 ClientApp/test/boot-tests.ts 文件.

Next, I changed the ClientApp/test/boot-tests.ts file.

更改此行:

const context = require.context('../app/', true, /\.spec\.ts$/);

对此:

const context = require.context('../app', true, /\.ts$/);

(上面的)直接来自下面的第一个参考文献.

This (above) is directly from first reference below.

接下来,我将 ClientApp/test/karma.conf.js 内容替换为:

Next, I replaced the ClientApp/test/karma.conf.js content with this:

const path = require('path');

var webpackConfig = require('../../webpack.config.js')().filter(config => config.target !== 'node')[0];
webpackConfig.module.rules.push({
    test: /\.ts$/,
    include: [path.resolve(__dirname, '../app')],
    use: {
        loader: 'istanbul-instrumenter-loader?force-sourcemap=true',
        options: { esModules: true }
    },
    enforce: 'post',
    exclude: [/\.spec\.ts$/]
});

module.exports = function (config) {
    config.set({
        basePath: '.',
        frameworks: ['jasmine'],
        files: ['../../wwwroot/dist/vendor.js', './boot-tests.ts'],
        preprocessors: {
            './boot-tests.ts': ['webpack']
        },
        reporters: ['progress', 'karma-remap-istanbul'],
        port: 9876,
        colors: true,
        logLevel: config.LOG_INFO,
        autoWatch: true,
        browsers: ['Chrome'],
        mime: { 'application/javascript': ['ts', 'tsx'] },
        singleRun: true,
        webpack: webpackConfig,
        webpackMiddleware: { stats: 'errors-only' },
        remapIstanbulReporter: {
            reports: {
                html: 'ClientApp/test/coverage',
                'text-summary': null
            }
        }
    });
};

现在,当我从应用程序的根目录运行npm test时,我会在 ClientApp/test/coverage 文件夹中建立覆盖报告(打开 index.html >在您选择的浏览器中).我还在 karma.conf.js 的报告选项中添加了text-summary,因此您也可以在命令行上获得摘要.

Now, when I run npm test from the root of the application, I get coverage reporting built in the ClientApp/test/coverage folder (open the index.html in a browser of you choice). I also added text-summary to the reports options in the karma.conf.js, so you get a summary on the command line, too.

如果希望在更新代码和单元测试时运行并刷新它,则可以将 karma.conf.js 中的singleRun更改为false.我在移至Angular 5.0.0后尝试使用模板进行所有操作时遇到了一个问题.使用ng 5.0.0时,会输出一个编译时警告,这会导致karma反复编译,而不管代码是否更改. ng 4.2.5并没有这个问题,它是Core 2.0模板开箱即用的版本.

You can change the singleRun in the karma.conf.js to false, if you want this to run and refresh as you make updates to code and unit tests. I ran into an issue where this when I tried all of this with the template after moving to Angular 5.0.0. With ng 5.0.0, a compile time warning is output, which is causing karma to recompile over and over, whether there are changes to code or not. I didn't have this issue with ng 4.2.5, which is the version the Core 2.0 template is using out of the box.

QIQO.Core.Ng.Coverage 是我的一个项目我已经添加了这些更改,供您查看.

QIQO.Core.Ng.Coverage is where I have a project that I have added these changes for you to look at if you like.

参考:

Angular2SpaCodeCoverage /aspnet/JavaScriptServices"rel =" nofollow noreferrer> JavaScriptServices Wiki.

Angular2SpaCodeCoverage from the JavaScriptServices wiki.

这将为您提供大部分帮助,但是对 karma.conf.js 进行更改的部分不太正确,并且不适用于最新版本的模板或webpack(在撰写本文时,我正在使用3.8.1). sourcemap-istanbul-instrumenter-loader包的用法似乎也不再起作用.这引出我下一个参考.

This will get you most of the way there, but the section with the changes to the karma.conf.js were not quite right, and didn't work with the latest version of the template, or webpack (and I am using 3.8.1 at the time I am writing this). It's usage of the sourcemap-istanbul-instrumenter-loader package didn't seem to work anymore either. Which leads me to the next reference.

问题:Angular 2和webpack 2的代码覆盖范围

正是本期话题的最后2篇帖子中的信息帮助我总结了这一篇.感谢 Tdortiz !.技巧是将options: { esModules: true }添加到 karma.conf.js 中,并使用istanbul-instrumenter-loader而不是sourcemap-istanbul-instrumenter-loader.

It was the information in the last 2 posts in this issue thread that helped me wrap this one up. Thanks to Tdortiz!. Adding options: { esModules: true } to the karma.conf.js, and using istanbul-instrumenter-loader rather than sourcemap-istanbul-instrumenter-loader were the tricks.

这篇关于向ASP.NET Core Angular 2 Starter应用程序添加代码覆盖率的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆