[cypress]组件测试覆盖率(coverage)

2,359 阅读3分钟

“我正在参加「掘金·启航计划」”

背景

在使用 cypress 做组件测试时遇到一个问题,如何统计组件测试的覆盖率?
根据 cypress 关于覆盖率的介绍,cypress 并不提供这个功能,建议通过 nyc 这个库或通过babel插件 babel-plugin-istanbul 在编译时集成到项目中;

Cypress does not instrument your code - you need to do it yourself. The golden standard for JavaScript code instrumentation is the battle-hardened Istanbul and, luckily, it plays very nicely with the Cypress. You can instrument the code as a build step through one of two ways:

Using the nyc module - a command-line interface for the Istanbul library  
As part of your code transpilation pipeline using the babel-plugin-istanbul tool.  

其实这两种方式都是基于 Istanbul 实现的, 同时 cypress 提供了一个插件 @cypress/code-coverage 来收集 Istanbul instrument 生成的结果;

对于没有接触过 Istanbul 的我来说,看的有点晕。本文主要是记录下在使用 cypress 对 vue 进行组件测试时,如何进行覆盖率统计。

cypress coverage

进行代码覆盖统计有三步,instrument/collect/report(插桩、收集、展示)。
先给结论:
1、通过 vite-plugin-istanbul 进行 instrument;
2、通过 @cypress/code-coverage 进行收集;
3、通过 nyc 进行数据展示;

下面展开讲一下为什么这么选择和各个方案的实践。

instrument

instrument 的方式挺多的,暂时只对 cypress 推荐的两种方式进行尝试和实现;
1、对完成编译打包的文件进行 instrument, e.g. 使用 nyc 进行 instrument

// 将 vite 打包后的dist目录拷贝到coverage目录,将新目录打包的js进行 instument(区分测试目录和实际打包目录,这里根据自己需求做就好了)
npm run build // 打包
cp -r ./dist ./coverage // 复制出来做测试
npx nyc instrument ./dist ./coverage  // 进行 instrument

执行了 instrument 后可以查看输入目录 coverage 已生成了 instrument 后的代码(后面再聊如何收集)。

2、动态 instrument, 使用对应插件进行动态 instrument, e.g. vite-plugin-istanbul(需要注意区分development/production):

// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import istanbul from 'vite-plugin-istanbul';

// https://vitejs.dev/config/
export default defineConfig({
  build: {
    sourcemap: true
  },
  plugins: [
    vue(),
    istanbul({
      include: 'src/*',
      exclude: ['node_modules'],
      extension: ['.js', '.ts', '.vue'],
      requireEnv: false,
      forceBuildInstrument: false
    })
  ]
})

或者使用babel插件 babel-plugin-istanbul 进行动态instrument, 但我目前基本都使用vite来构建项目,暂时不去了解 babel 插件的使用了。

collect

完成了 instrument 后,会在页面其实已生成了 window.coverage 对象, 并根据代码执行情况更新覆盖率。
在我项目的组件测试中,cypress 是通过 vite 来启动测试服务的,cypress的配置如下:

// cypress.config.ts
import { defineConfig } from "cypress"

export default defineConfig({
  component: {
    devServer: {
      framework: "vue",
      bundler: "vite",
    }
  }
});

所以我在项目根目录下的 vite.config.ts 配置进行 intrument 即可。然后通过 @cypress/coverage 插件进行 coverage 数据收集:

// cypress.config.ts
import { defineConfig } from "cypress"
import task from '@cypress/code-coverage/task'

export default defineConfig({
  component: {
    devServer: {
      framework: "vue",
      bundler: "vite",
    },
    setupNodeEvents(on, config) {
      task(on, config)
      // include any other plugin code...
      
      // It's IMPORTANT to return the config object
      // with any changed environment variables
      return config
    }
  },
  video: false
});

注: 如果需要coverage .vue后缀文件,可以通过命令行或者 .nycrc 文件增加 extension 配置, e.g.

// .nycrc
{
  "extension": [
    ".js",
    ".ts",
    ".vue"
  ]
}

report

通过 nyc report 命令进行展示, 默认是 text 输出,可以在命令行或者配置文件进行配置, e.g.

nyc report --reporter=lcov --reporter=text // 输出 text 并在默认 coverage 目录生成html展示文件

image.png

参考文档

1、E2E-code-coverage: docs.cypress.io/guides/tool…
2、vite-plugin-istanbul: github.com/ifaxity/vit…
3、vite-vue-cypress-code-coverage-example: github.com/bjankord/vi…
4、nyc: github.com/istanbuljs/…