monocart-coverage-reports 2.8.6 → 2.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -35,6 +35,7 @@
35
35
  * [Common issues](#common-issues)
36
36
  - [Unexpected coverage](#unexpected-coverage)
37
37
  - [Unparsable source](#unparsable-source)
38
+ - [JavaScript heap out of memory](#javascript-heap-out-of-memory)
38
39
  * [Debug for Coverage and Sourcemap](#debug-for-coverage-and-sourcemap)
39
40
  * [Integration with Any Testing Framework](#integration-with-any-testing-framework)
40
41
  * [Integration Examples](#integration-examples)
@@ -141,6 +142,9 @@ For more information, see [Command Line](#command-line)
141
142
  - `codecov`
142
143
  - coverage data for [Codecov](https://docs.codecov.com/docs/codecov-custom-coverage-format), see [example](https://app.codecov.io/github/cenfun/monocart-coverage-reports)
143
144
 
145
+ - `codacy`
146
+ - coverage data for [Codacy](https://api.codacy.com/swagger#tocscoveragereport) API
147
+
144
148
  - `console-summary` shows coverage summary in the console
145
149
 
146
150
  ![](./assets/console-summary.png)
@@ -881,6 +885,15 @@ const coverageOptions = {
881
885
  }
882
886
  ```
883
887
 
888
+ ### JavaScript heap out of memory
889
+ When there are a lot of raw v8 coverage files to process, it may cause OOM. We can try the following Node.js options:
890
+ ```sh
891
+ - run: npm run test:coverage
892
+ env:
893
+ NODE_OPTIONS: --max-old-space-size=8192
894
+ ```
895
+
896
+
884
897
  ## Debug for Coverage and Sourcemap
885
898
  > Sometimes, the coverage is not what we expect. The next step is to figure out why, and we can easily find out the answer step by step through debugging.
886
899
  - Start debugging for v8 report with option `logging: 'debug'`
@@ -900,6 +913,11 @@ When `logging` is `debug`, the raw report data will be preserved in `[outputDir]
900
913
 
901
914
  ![](./assets/debug-sourcemap.png)
902
915
 
916
+ - Show time logs with env `MCR_LOG_TIME`
917
+ ```js
918
+ process.env.MCR_LOG_TIME = true
919
+ ```
920
+
903
921
  ## Integration with Any Testing Framework
904
922
  - API
905
923
  - Collecting coverage data when any stage of the test is completed, and adding the coverage data to the coverage reporter. `await mcr.add(coverageData)`
package/README.zh-Hans.md CHANGED
@@ -35,6 +35,7 @@
35
35
  * [常见问题](#common-issues)
36
36
  - [Unexpected coverage](#unexpected-coverage)
37
37
  - [Unparsable source](#unparsable-source)
38
+ - [JavaScript heap out of memory](#javascript-heap-out-of-memory)
38
39
  * [如何调试覆盖率数据和查看sourcemap](#debug-for-coverage-and-sourcemap)
39
40
  * [如何跟其他框架集成](#integration-with-any-testing-framework)
40
41
  * [集成的例子](#integration-examples)
@@ -141,6 +142,9 @@ mcr node my-app.js -r v8,console-details
141
142
  - `codecov`
142
143
  - 专属支持[Codecov](https://docs.codecov.com/docs/codecov-custom-coverage-format)的报告, see [example](https://app.codecov.io/github/cenfun/monocart-coverage-reports)
143
144
 
145
+ - `codacy`
146
+ - 专属支持[Codacy](https://api.codacy.com/swagger#tocscoveragereport) API的报告
147
+
144
148
  - `console-summary` 在控制台显示覆盖率概要
145
149
 
146
150
  ![](./assets/console-summary.png)
@@ -884,6 +888,15 @@ const coverageOptions = {
884
888
  }
885
889
  ```
886
890
 
891
+ ### JavaScript heap out of memory
892
+ 内存溢出问题可能出现在有太多的原生V8覆盖率文件要处理. 我们可以使用Node.js的一个选项来增加内存使用:
893
+ ```sh
894
+ - run: npm run test:coverage
895
+ env:
896
+ NODE_OPTIONS: --max-old-space-size=8192
897
+ ```
898
+
899
+
887
900
  ## Debug for Coverage and Sourcemap
888
901
  > 当你觉得覆盖率存在问题的时候,`MCR`支持自行调试来核验覆盖率的准确性
889
902
  - 首先打开调试设置`logging: 'debug'`
@@ -903,6 +916,11 @@ const coverageOptions = {
903
916
 
904
917
  ![](./assets/debug-sourcemap.png)
905
918
 
919
+ - 使用环境变量`MCR_LOG_TIME`显示时间日志
920
+ ```js
921
+ process.env.MCR_LOG_TIME = true
922
+ ```
923
+
906
924
  ## Integration with Any Testing Framework
907
925
  通用集成方案
908
926
  - 通过API接口在程序集成
@@ -147,8 +147,7 @@ const handleLinesCoverage = (bytes, locator, ignoredRanges) => {
147
147
  blank: blankCount,
148
148
  comment: commentCount
149
149
  };
150
- // data lines for codecov
151
- // https://docs.codecov.com/docs/codecov-custom-coverage-format
150
+ // data lines
152
151
  const dataLines = {};
153
152
 
154
153
  // no ignore items
package/lib/generate.js CHANGED
@@ -90,6 +90,7 @@ const getReportGroup = (reports, lcov, dataType) => {
90
90
 
91
91
  // both
92
92
  'codecov': 'both',
93
+ 'codacy': 'both',
93
94
  'console-details': 'both',
94
95
  'console-summary': 'both',
95
96
  'raw': 'both'
@@ -280,6 +281,42 @@ const handleCodecovReport = async (reportData, reportOptions, options) => {
280
281
  return Util.relativePath(jsonPath);
281
282
  };
282
283
 
284
+ const handleCodacyReport = async (reportData, reportOptions, options) => {
285
+ const codacyOptions = {
286
+ outputFile: 'codacy.json',
287
+ ... reportOptions
288
+ };
289
+
290
+ const jsonPath = path.resolve(options.outputDir, codacyOptions.outputFile);
291
+
292
+ // https://api.codacy.com/swagger#tocscoveragereport
293
+ const fileReports = [];
294
+ reportData.files.forEach((item) => {
295
+ const { sourcePath, data } = item;
296
+
297
+ const coverage = {};
298
+ for (const [key, value] of Object.entries(data.lines)) {
299
+ if (typeof value === 'number') {
300
+ coverage[key] = value;
301
+ } else {
302
+ // partial coverage not supported?
303
+ coverage[key] = 0;
304
+ }
305
+ }
306
+
307
+ fileReports.push({
308
+ filename: sourcePath,
309
+ coverage
310
+ });
311
+ });
312
+ const codacyData = {
313
+ fileReports
314
+ };
315
+
316
+ await Util.writeFile(jsonPath, JSON.stringify(codacyData));
317
+ return Util.relativePath(jsonPath);
318
+ };
319
+
283
320
  const handleConsoleDetailsReport = (reportData, reportOptions, options) => {
284
321
  const cdOptions = {
285
322
  maxCols: 50,
@@ -464,6 +501,7 @@ const generateCoverageReports = async (dataList, sourceCache, options) => {
464
501
 
465
502
  const buildInBothReports = {
466
503
  'codecov': handleCodecovReport,
504
+ 'codacy': handleCodacyReport,
467
505
  'console-details': handleConsoleDetailsReport,
468
506
  'console-summary': handleConsoleSummaryReport,
469
507
  'raw': handleRawReport
@@ -854,9 +892,16 @@ const resolveEntrySourceMap = (entry, sourceMapCache) => {
854
892
  }
855
893
  };
856
894
 
857
- const readCoverageData = (item, entryFilter, sourceCache) => {
895
+ const readCoverageData = async (dir, filename, entryFilter, sourceCache) => {
858
896
 
859
- const json = item.json;
897
+ const content = await Util.readFile(path.resolve(dir, filename));
898
+ if (!content) {
899
+ return;
900
+ }
901
+ const json = JSON.parse(content);
902
+ if (!json) {
903
+ return;
904
+ }
860
905
 
861
906
  // raw v8 json
862
907
  let coverageData = json.result;
@@ -886,6 +931,26 @@ const readCoverageData = (item, entryFilter, sourceCache) => {
886
931
  return coverageData;
887
932
  };
888
933
 
934
+ const readSourceList = async (dir, sourceList) => {
935
+ const sourceCache = {};
936
+
937
+ for (const filename of sourceList) {
938
+ const content = await Util.readFile(path.resolve(dir, filename));
939
+ if (!content) {
940
+ continue;
941
+ }
942
+ const json = JSON.parse(content);
943
+ if (!json) {
944
+ continue;
945
+ }
946
+ if (json.url) {
947
+ sourceCache[json.url] = json;
948
+ }
949
+ }
950
+
951
+ return sourceCache;
952
+ };
953
+
889
954
  const readFromDir = async (mcr, dir) => {
890
955
 
891
956
  if (!dir || !fs.existsSync(dir)) {
@@ -894,56 +959,34 @@ const readFromDir = async (mcr, dir) => {
894
959
  }
895
960
 
896
961
  const files = fs.readdirSync(dir);
897
- const list = [];
962
+
963
+ const coverageList = [];
964
+ const sourceList = [];
965
+
898
966
  files.forEach((filename) => {
899
- if (filename.startsWith('coverage-')) {
900
- list.push({
901
- type: 'coverage',
902
- filename
903
- });
904
- return;
905
- }
906
- if (filename.startsWith('source-')) {
907
- list.push({
908
- type: 'source',
909
- filename
910
- });
967
+ // read all json files
968
+ if (filename.endsWith('.json')) {
969
+ // could be source files generated by register hooks
970
+ if (filename.startsWith('source-')) {
971
+ sourceList.push(filename);
972
+ } else {
973
+ coverageList.push(filename);
974
+ }
911
975
  }
912
976
  });
913
977
 
914
- if (!list.length) {
978
+ if (!coverageList.length) {
915
979
  Util.logInfo(`No coverage files in the dir: ${dir}`);
916
980
  return;
917
981
  }
918
982
 
919
- const contentList = await Promise.all(list.map((it) => Util.readFile(path.resolve(dir, it.filename))));
920
- const sourceCache = {};
921
- const coverageFiles = [];
922
-
923
- contentList.forEach((content, i) => {
924
- if (!content) {
925
- return;
926
- }
927
- const json = JSON.parse(content);
928
- if (!json) {
929
- return;
930
- }
931
- const item = list[i];
932
- if (item.type === 'source') {
933
- if (json.url) {
934
- sourceCache[json.url] = json;
935
- }
936
- } else {
937
- item.json = json;
938
- coverageFiles.push(item);
939
- }
940
- });
983
+ const sourceCache = await readSourceList(dir, sourceList);
941
984
 
942
985
  const entryFilter = mcr.getEntryFilter();
943
986
 
944
987
  const results = [];
945
- for (const item of coverageFiles) {
946
- const coverageData = readCoverageData(item, entryFilter, sourceCache);
988
+ for (const filename of coverageList) {
989
+ const coverageData = await readCoverageData(dir, filename, entryFilter, sourceCache);
947
990
  if (coverageData) {
948
991
  const res = await mcr.add(coverageData);
949
992
  results.push(res);
package/lib/index.d.ts CHANGED
@@ -107,6 +107,9 @@ declare namespace MCR {
107
107
  ['codecov'] | ["codecov", {
108
108
  outputFile?: string;
109
109
  }] |
110
+ ['codacy'] | ["codacy", {
111
+ outputFile?: string;
112
+ }] |
110
113
  ['console-summary'] | ['console-summary', {
111
114
  metrics?: Array<"bytes" | "statements" | "branches" | "functions" | "lines">;
112
115
  }] |
@@ -190,7 +193,7 @@ declare namespace MCR {
190
193
  branches?: CoverageRange[];
191
194
  functions?: CoverageRange[];
192
195
  ignores?: IgnoredRange[];
193
- /** codecov json format */
196
+ /** common json format */
194
197
  lines: {
195
198
  [key: string]: number | string;
196
199
  };
package/lib/index.js CHANGED
@@ -141,6 +141,9 @@ class CoverageReport {
141
141
  return;
142
142
  }
143
143
 
144
+ // GC, no OOM
145
+ this.fileCache.clear();
146
+
144
147
  const { dataList, sourceCache } = inputData;
145
148
 
146
149
  // empty output dir except cache dir before generate reports
@@ -161,16 +164,21 @@ class CoverageReport {
161
164
 
162
165
  const coverageResults = await generateCoverageReports(dataList, sourceCache, this.options);
163
166
 
164
- if (this.logging !== 'debug') {
165
- Util.rmSync(this.options.cacheDir);
166
- }
167
-
168
167
  const onEnd = this.options.onEnd;
169
168
  if (typeof onEnd === 'function') {
170
169
  await onEnd.call(this, coverageResults);
171
170
  }
172
171
 
173
- Util.logTime(`generated coverage reports: ${EC.cyan(coverageResults.reportPath)}`, time_start);
172
+ // remove cache dir after finished
173
+ if (!Util.isDebug()) {
174
+ Util.rmSync(this.options.cacheDir);
175
+ }
176
+
177
+ let reportPath = '';
178
+ if (coverageResults.reportPath) {
179
+ reportPath = EC.cyan(coverageResults.reportPath);
180
+ }
181
+ Util.logTime(`generated coverage reports: ${reportPath}`, time_start);
174
182
 
175
183
  return coverageResults;
176
184
  }