Angular + Cypress 代码覆盖率报告不起作用

标签 angular code-coverage cypress istanbul nyc

我一直试图让 Cypress 代码覆盖率与我的 Angular 生产项目一起工作,但无济于事。
为了尝试帮助诊断它,我创建了一个最小的实现项目,以确保我没有在生产版本中引入任何奇怪的东西,我认为我不会,因为同样的问题仍在发生。它开始让我发疯!
我使用了一些引用资料,据我所知,我已经准备好了我需要的东西:

  • Cypress Coverage Documentation
  • Article 1
  • Code Example (older dependencies)

  • 据我所知,Angular 和 Cypress 端都已连接好,并且正在 .nyc_output 文件夹中获得输出和覆盖率报告。然而,该报告并未表明 typescript 行覆盖率或包括这些统计数据。
    enter image description here
    enter image description here
    我见过this但似乎没有帮助。
    代码检测(webpack 扩展 + angular.json):
    module.exports = {
      module: {
        rules: [
          {
            test: /\.(js|ts)$/,
            loader: "istanbul-instrumenter-loader",
            options: { esModules: true },
            enforce: "post",
            include: require("path").join(__dirname, "..", "src"),
            exclude: [
              /\.(e2e|spec)\.ts$/,
              /node_modules/,
              /(ngfactory|ngstyle)\.js/,
            ],
          },
        ],
      },
    };
    
    "serve": {
      "builder": "ngx-build-plus:dev-server",
      "options": {
        "browserTarget": "architecture-testing:build",
        "extraWebpackConfig": "./cypress/coverage.webpack.js",
        "sourceMap": true
      },
      "configurations": {
        "production": {
          "browserTarget": "architecture-testing:build:production"
        }
      }
    }
    
    Cypress 似乎正在记录和保存覆盖范围:
    const registerCodeCoverageTasks = require("@cypress/code-coverage/task");
    
    module.exports = (on, config) => {
      registerCodeCoverageTasks(on, config);
    
      return config;
    };
    
    enter image description here
    enter image description here
    out.json 似乎具有正确的文件和代码映射:
    enter image description here
    enter image description here
    enter image description here :
    package.json(纽约配置+ deps):
    {
      "name": "architecture-testing",
      "version": "0.0.0",
      "scripts": {
        "postinstall": "ngcc",
        "ng": "ng",
        "start": "ng serve",
        "build": "ng build",
        "test": "ng test",
        "lint": "ng lint",
        "e2e": "ng e2e",
        "precypress": "rimraf .nyc_output coverage",
        "cypress": "ng run architecture-testing:cypress-run",
        "cypress:open": "cypress open",
        "cypress:run": "cypress run"
      },
      "nyc": {
        "extends": "@istanbuljs/nyc-config-typescript",
        "all": true,
        "exclude": [
          "coverage/**",
          "cypress/**",
          "**/*.spec.ts"
        ]
      },
      "private": true,
      "dependencies": {
        "@angular/animations": "~9.1.9",
        "@angular/common": "~9.1.9",
        "@angular/compiler": "~9.1.9",
        "@angular/core": "~9.1.9",
        "@angular/forms": "~9.1.9",
        "@angular/platform-browser": "~9.1.9",
        "@angular/platform-browser-dynamic": "~9.1.9",
        "@angular/router": "~9.1.9",
        "rxjs": "~6.5.4",
        "tslib": "^1.10.0",
        "zone.js": "~0.10.2"
      },
      "devDependencies": {
        "@angular-devkit/build-angular": "~0.901.7",
        "@angular/cli": "~9.1.7",
        "@angular/compiler-cli": "~9.1.9",
        "@briebug/cypress-schematic": "^3.3.0",
        "@cypress/code-coverage": "^3.8.1",
        "@cypress/webpack-preprocessor": "5.4.1",
        "@istanbuljs/nyc-config-typescript": "^1.0.1",
        "@types/node": "^12.11.1",
        "codelyzer": "^5.1.2",
        "cypress": "^4.8.0",
        "istanbul-instrumenter-loader": "^3.0.1",
        "istanbul-lib-coverage": "^3.0.0",
        "ngx-build-plus": "^9.0.6",
        "nyc": "^15.1.0",
        "rimraf": "^3.0.2",
        "source-map-support": "^0.5.19",
        "ts-loader": "7.0.5",
        "ts-node": "^8.3.0",
        "tslint": "~6.1.0",
        "typescript": "~3.8.3"
      }
    }
    
    规范文件:
    it('does something', () => {
      cy.visit('http://localhost:4200');
      cy.get('[data-cy=button-one]').click();
      cy.get('[data-cy=button-output]').should('have.text', 'you clicked button 1');
    });
    
    对不起,它太长了,但我不知道下一步要去哪里。如果你能指出我的任何方向,非常感谢。
    根据答案调查更新:
    查看@cypress/code-coverage 的过去版本,似乎我的问题是在插件的 v3.3.0 中引入的。在降级我的最小项目时,v3.2.* 的所有版本都对我有用。查看 v3.3.0 的文档更改后,自述文件中的关键信息是:
    **Note:** if you have `all: true` NYC option set, this plugin will check the produced `.nyc_output/out.json` before generating the final report. If the `out.json` file does not have information for some files that should be there according to `include` list, then an empty placeholder will be included, see [PR 208](https://github.com/cypress-io/code-coverage/pull/208).
    
    我原来的纽约配置是:
    "nyc": {
      "extends": "@istanbuljs/nyc-config-typescript",
      "all": true,
      "exclude": [
        "coverage/**",
        "cypress/**",
        "**/*.spec.ts"
      ]
    }
    
    因此,出于某种原因,即使我有在 out.json 中测试的文件的指标,也会创建第二个“空占位符”节点并覆盖随后的报告生成。我猜这可能是我的设置的错误或问题,所以会询问创建者。
    如果我将 nyc 配置更改为:
    "nyc": {
      "extends": "@istanbuljs/nyc-config-typescript",
      "all": true,
      "include": [
        "src/**/*.ts"
      ],
      "exclude": [
        "coverage/**",
        "cypress/**",
        "**/*.spec.ts"
      ]
    }
    
    这确实意味着如果我没有通过测试命中文件,它将不会作为空占位符包含在内,因为“所有”:true 不再存在。
    查看@briebug/cypress-schematic@3.3.0 这似乎没有引起任何问题(不使用他们的构建器也会发生同样的情况),但已被提出为一个 herehere .

    最佳答案

    比较 ang-cy-cov-example对于您的 package.json,主要区别在于他使用 @cypress/code-coverage@1.14.0,因为您拥有最新的 v3.8.1。

    改回这个 v1.14.0 可以正常使用您的设置。由于您的信息表明数据出现在 .nyc_output/out.json 中,我用命令行测试./node_modules/.bin/nyc report它可以在控制台中快速查看。

    比较 .nyc_output/out.json在两个版本之间,各个节点在结构上是相同的,即具有正确的部分(路径、语句映射、输入源映射等)。

    有两种类型的附加节点

  • 其他文件,例如 karma.conf.js、coverage.webpack.js、cy-ts-preprocessor.js、integration/spec.ts、support/commands.ts - 我们不感兴趣。
  • 我们感兴趣的文件在文件末尾重复,但重复项没有覆盖率指标。

  • 例如

    带有指标的 main.ts 的第一个副本
      "path-to\\src\\main.ts": {
        "path": "path-to\\src\\main.ts",
        "statementMap": {
             ...
          },
          "1": {
             ...
          },
          "2": {
             ...
          }
        },
        "fnMap": {},
        "branchMap": {
             ...
        },
        "s": {
          "0": 1,   // indicates one visit to this statement
          "1": 0,
          "2": 1
        },
        "f": {},
        "b": {
          "0": [
            0,
            1
          ]
        },
        "inputSourceMap": {
             ...
        },
        "_coverageSchema": "332fd63041d2c1bcb487cc26dd0d5f7d97098a6c",
        "hash": "5959c383a9744c99a600a28ff82b12f0a540c5e6"
      },
    

    没有指标的 main.ts 的第二个副本
      "path-to/src/main.ts": {
        "path": "path-to/src/main.ts",
        "statementMap": {},
        "fnMap": {},
        "branchMap": {},
        "s": {},          // no metrics recorded here
        "f": {},
        "b": {}
      },
    

    因此,结论是 NYC 报告正在用第二个节点的空指标替换第一个节点指标。

    我跳过了版本,v3.2.0 是我发现的最新版本。

    添加节点模块时也要注意这个警告,但不能说它是否是一个促成因素。

    warning " > @briebug/cypress-schematic@3.3.0" has incorrect peer dependency "cypress@^3.6.1"



    故障点

    基本问题在于 task-utils.js。

    引用 getting allFiles
    const allFiles = globby.sync(patterns, { absolute: true })
    

    哪里globby即使在 Windows 上也返回带有正斜杠的路径

    和引用 getting coveredPaths
    const coveredPaths = coverageKeys.map(key => nycCoverage[key].path)
    

    key 已保存在 out.json 中的位置在 Windows 中使用反斜杠。

    一个快速的解决方法是此时标准化路径
    const coveredPaths = coverageKeys.map(key => nycCoverage[key].path)
      .map(path => path.replace(/\\/g, '/'))  // Compare "normalized" paths 
    

    修补 '/node_modules/@cypress/code-coverage/task-utils.js' 修复了这个问题。

    关于Angular + Cypress 代码覆盖率报告不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62346770/

    相关文章:

    html - 检测 Angular 4 中的实时窗口大小变化

    java - 在 Spring boot 中添加 catch block 的代码覆盖率

    testing - 编写路径覆盖工具

    javascript - Allure 报告与 cypress 集成时得到 NaN%

    javascript - Cypress Codebuild 项目无法启动

    Angular sourceMap 损坏

    Angular 4 Material 显示带有ngFor和ngModel的formArrayName

    java - 使用代码覆盖工具时,在此之前的构造函数中的代码或生成的类文件中的 super 代码

    javascript - 字符串为空时柏树中的 .type() 方法

    angular - 重新正确安装 Angular